tags:

views:

205

answers:

7

Take look at the code that follows.

"Hello " "World!";
"The number is ", 37;
int x=23;
char *y="232";
x,x+2,x*3;
atoi(y) - x;

It is a perfectly valid fragment of C(99) source. But! All that expressions return to nowhere! How can one trace or even use all this anonymous values? Where are they stored and what is their purpose?

+8  A: 

These values go nowhere. You can not retrieve them. In fact, most are optimized out by the compiler.

That entire fragment can be simplified to atoi("232") because function calls usually can't be optimized out.

Forrest
`atoi` is defined by the C standard in such a way that it has no side effects, so a good compiler will optimize it out too. (Redefining `atoi` (with external linkage) in your program has undefined behavior so the compiler is free to assume it's not redefined as long as there is no static definition in the current file scope.)
R..
+3  A: 

Those particular expressions are useless. On the other hand, this is allowed because some expressions have side effects(and perhaps return values), and sometimes only the side effect is needed.

Bwmat
+2  A: 

Expressions that don't have side effects aren't particularly useful. Usually you find a function call at those places, and the function body actually causes some state change in the program.

Languages have lots of silly ways to do nothing. Consider the C statement:

  ;

It doesn't do anything.

Ira Baxter
+2  A: 

Are you asking if this:

int main() {
   1;
}

is valid C code? If so, yes it is, and always has been.

anon
Is it valid, even if you don't `return` at the end? I know most compilers will grudgingly accept that, but I didn't think it was strictly valid not to return at the end of any function (except `main` in C++).
Chris Lutz
@Chris Sigh. My point was about the expression 1, not the return value of main.
anon
I'm pretty sure that not explicitly returning from main has always been valid.
DeadMG
@DeadMG - Nope. It was allowed as a misfeature in C++, and more recently C99, but it was never part of standard C before then. @Neil - Sorry to be so pedantic. I understood your point, but was worried (probably unnecessarily) that it might be a bit misleading
Chris Lutz
+1  A: 

The comma operator evaluates expressions in order and returns the value of the last one. It's only useful if the previous expressions perform side effects like assignment.

So far as I can tell, the use of comma here is superfluous, and the expressions' values are being thrown away - you can't retrieve them. Unless you're writing these lines in the context of a special C interpreter...?

Owen S.
@Owen S. "special C interpreter"? What do you mean? An interpreter of mine that uses C's grammar, but evaluates expressions the way I define?
Rizo
I am not sure about "returns value of the last one". Just made some testing, and it seems it is not: `y=0; x = ++y, y, ++y, y` assigns 1 to x in my tests (and at the end y is 2 of course)
ShinTakezou
@Rizo: Yes. Such things exist but aren't used widely to my knowledge. Interpreters may be able to do something with those statements that a traditional C compiler wouldn't.
Owen S.
@Shin: Write "x = (++y, y, ++y, y);" and see what you get.
Owen S.
@Owen S, got it! But what the std says? Is the , operator `a, b` simply or it should be always `(a, b)`... what is then `a, b` and why `a, b, c` is different from `(a, b, c)`? - luckly I've never used `,` (maybe "unconsciously" only in `for`)!!
ShinTakezou
@Shin: It's simply "a, b" but "," has less precedence than "=" so parens are required if you want to take advantage of this feature of ",". It's arcane C though. I've never had cause to use "," in this way.
Owen S.
+2  A: 

The same happens every time you call printf(3) without checking its return value, which is discarded. The function call though might have side-effects (printf(3) certainly does), so the instructions to execute it are still generated. Most modern compilers will remove most of the statements you listed given appropriate optimization flags.

If you really want to see what happens, compile your source to assembly (-S option for GCC) with (say -O2) and without optimization and trace the instructions.

Nikolai N Fetissov
Not quite the same because printf has (arguably useful) side effects. None of the examples in the question have any side effects.
R..
Didn't I say that?
Nikolai N Fetissov
+1  A: 

From a functional point of view, all those expressions' results are lost. If good optimizations are at work, they are not computed at all. But let us suppose they are. In this case "where" the results are available depends on how the compiler translated the code, a fact that can be considered unpredictable.

On x86 machines, you can think that integer results and pointer results are stored into eax (that then will be trashed), but it is just a supposition; if it is true for a specific compiler and code, it could be not for another compiler or if you change a bit the code. It could also happen that the values are pushed on the stack, which then it's incremented again, so that, until it is not reused, you can find the value on the stack. Same arguments as for eax can be done.

The part tied through the comma are someway different. Things like a, b are read as "execute a, discard any result and then execute b", so that the result of a is lost "by definition" (of course, looking at the asm code, you could also in this case find that it is still available somewhere, but likely it is indeed not after b is evaluated)

ShinTakezou
Sorry, I didn't understand: is the result of `a` is still available in `b`?Where can I find more information about the comma operator?
Rizo
@Rizo into standard, I believe, but I don't know where you can download it. For sure here there are people aware of it. In `a, b` as already said, a is evaluated and the result (if any) is dropped (lost); then b is evaluated and the result taken. E.g. `x = a, b;` compute a, the assign to x the result of the evaluation of b. If a has no side effects for b, you can write `x = b; a;` or `a; x = b`.
ShinTakezou