Plz explain me the following code

K

Keith Thompson

jameskuyper said:
Does a compiler that generates such code satisfy the "restrictions
placed upon you by that platform"? If so, there's no problem. If not,
then the platform's restrictions are sufficient reason to reject that
compiler; there's no need to mention them in the C standard, so as to
find a second reason for rejecting it.

It depends on just what the platform's restrictions are.

A platform (depending on just what "platform" means) might specify
certain behavior for an attempt to dereference a null pointer, but
I'd expect such restrictions to be stated in terms of executing
certain machine code. If a given chunk of C code is compiled to
machine code that *doesn't* actually dereference a null pointer,
then any platform-level statements would be inapplicable.

Or are you suggesting that the platform would impose restrictions on
the optimizations that can be performed by a C (or other language)
compiler? If so, I think that specifying those restrictions in a
precise and meaningful way could be extraordinarily difficult.
 
J

jameskuyper

Keith said:
It depends on just what the platform's restrictions are.

A platform (depending on just what "platform" means) might specify
certain behavior for an attempt to dereference a null pointer, but
I'd expect such restrictions to be stated in terms of executing
certain machine code. If a given chunk of C code is compiled to
machine code that *doesn't* actually dereference a null pointer,
then any platform-level statements would be inapplicable.

So if the standard were modified, as described above, to mandate that
those restrictions be followed, that modification would not render
such a compiler non-conforming, because those restrictions are
inapplicable to it.
Or are you suggesting that the platform would impose restrictions on
the optimizations that can be performed by a C (or other language)
compiler? If so, I think that specifying those restrictions in a
precise and meaningful way could be extraordinarily difficult.

I'm not suggesting it, I'm just making a point that includes that as
one possibility. My point was that if the relevant restrictions
applied to how compilers convert C source code into machine code, then
it would be redundant for the C standard to also require obedience to
them. If they don't apply to how compilers convert C source code into
machine code, then having the standard require obedience to them would
have no impact. Either way, such a modification to the standard would
be pretty pointless.
 
S

Seebs

The trouble with relying on the compiler is that it can't tell what
matters and what does not. Currently, if i write:

x = f() + g();

I am saying that I don't care about the order of the calls. If an
order were mandated with permission to reorder when it can't matter
almost any side-effect at all in f or g would prevent re-ordering.
Maybe f and g have logging calls. These are side-effects, but I don't
care what order they occur in -- that is my choice, but the compiler
can't ever know that! Such cases may be rare enough to not matter in
practise, of course.

Good example! Logging calls are in fact a case where I may genuinely
not care about the order of side effects, even though it's quite possible
that there will be observable differences betwween two possible choices.

C lets me specify what I want:

x = f();
x += g();

but also lets me express "really, either's fine".

-s
 
P

Processor-Dev1l

Processor-Dev1l wrote:

[...]
Someone once said: Every program can be shorten by one useless line
and every program contains at least one wrong line.
It means you can shorten your code to one line that is wrong :).

That same person probably believes that there exists a compression algorithm
that can guarantee that the result will be smaller than the original,
regardless of the input.
Well, I don't work on new C compiler and I don't work with standard C
at all.
I work with modified C, which uses IBM compiler (made especially for
zOS system) for support of macros and system environment of zOS.

Fine.  But, unless that vendor has explicitly stated that use of constructs
such as "i = i++" will exhibit defined behavior, you are still invoking UB,
and there is no guarantee that the observed behavior won't change.

[...]
Main reason why I thought this code can work is I spent really a lot
of times on HLL languages (like java, c#), where such constructions
are not undefined and they have their rules.
i = i++ + ++j;
but be translated by managed code as
++j;
i = i + j;
i++;

In your example, why does j's increment take place before the assignment,
but i's takes place after?
I can answer this question quite easily :)
this code
for(i=0;i<5;i++) printf("%d", i);
will write 01234, but
for(i=0;i<5;++i) printf("%d", i);
will write 12345
other explanation: n++ is first processed, then increased
++n is first increased and then processed.
I have never touched C#, and I don't know Java well enough to comment on
this particular construct.  But, if you were to ask here, most would agree
that requiring that interpretation puts an unnecessary burden on the
compiler, and can prevent it from optimizing the code.

What do C# and Java say about:

     i = j++ + ++i;

 From your comment above, I will assume that they require it be equivalent to:

     ++i;
     i = i + j;
     j++; Yeah, that's right

Must i actually be incremented prior to performing the addition, or is the
compiler allowed to optimize it to be:

     i += j + 1;
     j++;
Well, I can't say about this one, because both Java and c# contains
just half-compiler
 
P

Processor-Dev1l

Processor-Dev1l wrote:
<snip>




Main reason why I thought [i=i++] can work is I spent really a lot
of times on HLL languages (like java, c#), where such constructions
are not undefined and they have their rules.
i = i++ + ++j;
but be translated by managed code as
++j;
i = i + j;
i++;
In your example, why does j's increment take place before the assignment,
but i's takes place after?
I have never touched C#, and I don't know Java well enough to comment on
this particular construct.  But, if you were to ask here, most would agree
that requiring that interpretation puts an unnecessary burden on the
compiler, and can prevent it from optimizing the code.
What do C# and Java say about:
     i = j++ + ++i;

I was curious so I went digging in the java spec. I couldn't actually
find a mention of this (but this is probably more a reflection of how
carefully I searched).

java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.7

possibly a combination of "Evaluate Left-Hand Operand First" and
"Evaluate
Operands before Operation" leads to this behaviour
 From your comment above, I will assume that they require it be equivalent to:
     ++i;
     i = i + j;
     j++;
Must i actually be incremented prior to performing the addition, or is the
compiler allowed to optimize it to be:
     i += j + 1;
     j++;

<snip>

Really really hard to say. Either c# or java are compiler into managed
code (which is fully compiled when ran), it makes the code 100%
portable
 
K

Keith Thompson

jameskuyper said:
Keith said:
jameskuyper said:
Kenneth Brody wrote: [...]
Except that nothing requires that:

char foo(void)
{
return *(char *)NULL;
}

actually dereference a NULL pointer. The compiler is free to
generate any code is wishes, AFAIK, including code to (attempt
to) reformat the disk.

Does a compiler that generates such code satisfy the "restrictions
placed upon you by that platform"? If so, there's no problem. If not,
then the platform's restrictions are sufficient reason to reject that
compiler; there's no need to mention them in the C standard, so as to
find a second reason for rejecting it.

It depends on just what the platform's restrictions are.

A platform (depending on just what "platform" means) might specify
certain behavior for an attempt to dereference a null pointer, but
I'd expect such restrictions to be stated in terms of executing
certain machine code. If a given chunk of C code is compiled to
machine code that *doesn't* actually dereference a null pointer,
then any platform-level statements would be inapplicable.

So if the standard were modified, as described above, to mandate that
those restrictions be followed, that modification would not render
such a compiler non-conforming, because those restrictions are
inapplicable to it.

Hmm?

I was assuming the standard as currently written. If you want to
know what restrictions would apply to an implementation under a
hypothetical modified standard, I think you'll need to state more
precisely what modification you have in mind.

In the current standard, return *(char *)NULL; has undefined behavior.
How would its behavior be defined in your hypothetical modified
standard?
I'm not suggesting it, I'm just making a point that includes that as
one possibility. My point was that if the relevant restrictions
applied to how compilers convert C source code into machine code, then
it would be redundant for the C standard to also require obedience to
them. If they don't apply to how compilers convert C source code into
machine code, then having the standard require obedience to them would
have no impact. Either way, such a modification to the standard would
be pretty pointless.

Ok.

My point (I think) is that I don't know of any secondary standards
that impose this kind of restriction on C compiler code generation.

I think we're both arriving at the conclusion that it would be
pointless, but by different paths.
 
S

Seebs

I can answer this question quite easily :)

So you can!

Shame you can't answer it CORRECTLY.
this code
for(i=0;i<5;i++) printf("%d", i);
will write 01234, but
for(i=0;i<5;++i) printf("%d", i);
will write 12345

Incorrect. Both will write 01234.
other explanation: n++ is first processed, then increased
++n is first increased and then processed.

True enough.

If you wanted to illustrate your point, though, you'd have to write:
for (i = 0; i < 5; )
printf("%d", i++); /* or ++i */

(For extra credit: Explain why this should have been a while loop.)

-s
 
J

jameskuyper

Keith said:
jameskuyper said:
Keith said:
Kenneth Brody wrote: [...]
Except that nothing requires that:

char foo(void)
{
return *(char *)NULL;
}

actually dereference a NULL pointer. The compiler is free to
generate any code is wishes, AFAIK, including code to (attempt
to) reformat the disk.

Does a compiler that generates such code satisfy the "restrictions
placed upon you by that platform"? If so, there's no problem. If not,
then the platform's restrictions are sufficient reason to reject that
compiler; there's no need to mention them in the C standard, so as to
find a second reason for rejecting it.

It depends on just what the platform's restrictions are.

A platform (depending on just what "platform" means) might specify
certain behavior for an attempt to dereference a null pointer, but
I'd expect such restrictions to be stated in terms of executing
certain machine code. If a given chunk of C code is compiled to
machine code that *doesn't* actually dereference a null pointer,
then any platform-level statements would be inapplicable.

So if the standard were modified, as described above, to mandate that
those restrictions be followed, that modification would not render
such a compiler non-conforming, because those restrictions are
inapplicable to it.

Hmm?

I was assuming the standard as currently written. If you want to
know what restrictions would apply to an implementation under a
hypothetical modified standard, I think you'll need to state more
precisely what modification you have in mind.

The modification I'm talking about is the one Kenneth Brody suggested
in his message with the header "Date:Thu, 24 Sep 2009 13:17:54 -0400":
Perhaps replacing UB with something like "anything left undefined will, on
hosted implementations, behave in a manner consistent with the host"? So,
dereferencing a NULL pointer on Unix can't launch nuclear missiles, since
Unix says it should SEGV.

Basically, "I am not imposing any restrictions, but I do require that you
follow the restrictions placed on you by the host platform".

The essence of what I'm saying is that this modification is poorly
specified. I don't see any good way to improve it, either, or I would
have suggested one.
 
K

Keith Thompson

jameskuyper said:
The modification I'm talking about is the one Kenneth Brody suggested
in his message with the header "Date:Thu, 24 Sep 2009 13:17:54 -0400":

The essence of what I'm saying is that this modification is poorly
specified. I don't see any good way to improve it, either, or I would
have suggested one.

Then we're in agreement.
 
F

Flash Gordon

Kenneth said:
Flash said:
Seebs said:
In a language with more rigidly defined semantics, there may be no way
for me to express "these three things need to happen, but I don't care
in what order." [...]
The option of not specifying a thing you don't care about is
important for some applications.

Agreed. At times I would actually like *more* freedom to express that
I don't care about the order.

How much more freedom do you want than C's position that basically says
"except for crossing a sequence point, the compiler can pick any order
it wishes"?

Or do you want to specify that even sequence points don't matter?

a = b() + c();
b and c can occur in parallel because I know they won't interfere with
each other. In C you cannot express that level of freedom.
 
K

Keith Thompson

Eric Sosman said:
Since C has almost no notion of parallel activity to start with,
the lack of means to exert control over parallelism is unsurprising.

True. On the other hand, given:

a = d()*e() + f()*g();

the expressions d(), e(), f(), and g() can be evaluated in any of the
12 possible orders. In particular, the evaluates of the left and
right operands of the "+" can be interleaved:
Evalute d()
Evalute f()
Evaluate e()
Evaluate g()
Multiply d() * e()
Multiply f() * g()
Add the results of the two multiplications

Replace d()*e() with a call to:
int b(void) { return d()*e(); }
and f()*g() with a call to:
int c(void) { return f()*g(); }

and the compiler is no longer free to interleave the calls unless it
can prove that it doesn't affect either the result or any visible
side effects, and the programmer has no good way to specify that
it doesn't matter.

Not disagreeing, just letting my mind wander a bit.
 
N

Nobody

One of the goals of modern language design (a class of which C is not a
member) is to eliminate the concept of undefined behavior. It is a
necessary evil in C and assembler (and similar), but it is never
desirable.

It's desirable for performance reasons.

Not just to enable typical optimisations, but to allow pretty much any
realistic form of multi-threading.
 
F

Flash Gordon

Eric said:
Since C has almost no notion of parallel activity to start with,
the lack of means to exert control over parallelism is unsurprising.

Agreed. Some people said they wanted tighter ordering, I'm just saying
that at times I would like to give the compiler even more flexibility.
 
K

Keith Thompson

Eric Sosman said:
Keith said:
[...] On the other hand, given:

a = d()*e() + f()*g();

the expressions d(), e(), f(), and g() can be evaluated in any of the
12 possible orders. [...]

A personal question, Keith: Do you by any chance have six toes
on each foot? I understand that the variation isn't absurdly rare,
but I've never met anyone else who uses base twenty-two.

- Eric "counts higher in sandals" Sosman

No, I don't have six toes on each foot, and I fail to see why you
assumed that each of my feet must have the *same* number of toes.
This could just as easily be explained by assuming that I have 4
toes on one foot and 8 on the other.

(Or I could have done the math worng, but that's not worth
considering.)
 
E

Eric Sosman

Keith said:
Eric Sosman said:
Keith said:
[...] On the other hand, given:

a = d()*e() + f()*g();

the expressions d(), e(), f(), and g() can be evaluated in any of the
12 possible orders. [...]
A personal question, Keith: Do you by any chance have six toes
on each foot? I understand that the variation isn't absurdly rare,
but I've never met anyone else who uses base twenty-two.

- Eric "counts higher in sandals" Sosman

No, I don't have six toes on each foot, and I fail to see why you
assumed that each of my feet must have the *same* number of toes.
This could just as easily be explained by assuming that I have 4
toes on one foot and 8 on the other.

Ah! Of course -- Silly me; I'd thought of four and four
and four, but overlooked the possibility of eight plus four
plus four padding toes. Just be careful that all those padding
toes don't make you stumble over a trip representation.
 
P

Phil Carmody

Kenneth Brody said:
jameskuyper wrote:
[...]
The modification I'm talking about is the one Kenneth Brody suggested
in his message with the header "Date:Thu, 24 Sep 2009 13:17:54 -0400":

The essence of what I'm saying is that this modification is poorly
specified. I don't see any good way to improve it, either, or I would
have suggested one.

Note that I wasn't actually proposing a well-thought-out idea for an
actual change to C. It was mostly an off-the-cuff reply to a thread
which had started going towards "why does C even allow UB ... UB ==
bad language design".

And, thinking a little more about it, some UB doesn't even involve the
host. For example, fclose() on an invalid FILE*, or free() with a
pointer not from malloc() and friends. (Yes, the host may get
involved if the pointer itself is not valid, but what happens with a
valid pointer but just not pointing to what is expected?)

FILE* fp=fopen("foo", "r");
FILE* fp2=malloc(sizeof(*fp2));
memcpy(fp2, fp, sizeof(*fp2));
fclose(fp2);

fp2 of course does point to *what* was expected, it's just not *where*
it was expected.

Phil
 
P

Phil Carmody

Kenneth Brody said:
Which means it may not work. (I'm not sure if it's UB, however.)

7.19.3p6

"The address of the FILE object used to control a stream may be
significant; a copy of a FILE object need not serve in place of the
original."

I like comp.lang.c! Many thanks for doing the grepping. I don't like
the fluffiness of the wording, to be honest. The obligations should
be ascribed to the implementation, not to the object. However, it's
clearly a removal of obligation for any particular behaviout, and
we're given the rider that a lack of definition of behaviour is enough
to classify it as such, so I think it is indeed UB.

One has to question the sanity of the person who would come up with
code like that though - it's clearly deliberate mischief - as is the
following:

FILE* fp=fopen("foo", "r");
FILE* fp2=malloc(sizeof(*fp2));
memcpy(fp2, fp, sizeof(*fp2));
getc(fp);
memcpy(fp, fp2, sizeof(*fp));

Of course, exposing a FILE is clearly something that the language^W
implementation should avoid, so that the above won't even compile
(sans sizeof of an incomplete type).

Phil
 
M

Morris Keesan

Which means it may not work. (I'm not sure if it's UB, however.)

7.19.3p6

"The address of the FILE object used to control a stream may be
significant; a copy of a FILE object need not serve in place of the
original."

But note that in Phil Carmody's code, no FILE object is being copied.
He's copying a (FILE *) from fp into fp2, not a FILE.
 
B

Ben Bacarisse

Morris Keesan said:
But note that in Phil Carmody's code, no FILE object is being copied.
He's copying a (FILE *) from fp into fp2, not a FILE.

I think you've miss-read it. To copy a FILE * all you need is:

fp2 = fp;

The memcpy copies the thing pointed to by fp (well, the sizeof *fp2
bytes pointed to by fp).
 
P

Phil Carmody

Richard Heathfield said:
I'm not sure whether you are saying that the above won't compile under
current C rules, or that it ought not to compile if there were any
sanity in this world.

I'dn't've used "won't" had I the chance to write that sentence again.
Indeed, conditional was intended, sorry.
For the record, given a suitable framework (includes, a function
around it, etc) it compiles just fine, with no diagnostic messages
from the implementation I use.

I'm not sure how common an incomplete FILE type is. I wish it were
more common. I suspect there's never been a good need to expose its
innards.

Phil
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top