block statements, commas, and control expressions in C [duplicate] - c

This question already has answers here:
Are compound statements (blocks) surrounded by parens expressions in ANSI C?
(2 answers)
Closed 9 years ago.
I've tried to read the relavent sections of standard (secs 6.5 and 6.8 of c99), but this lead me to be more confused and without a clear answer. This is the code in question:
#include <stdio.h>
#include <time.h>
int t;
#define block {\
int temp = 1; \
t = time(NULL); \
if (t == (time_t) -1 && temp) puts("turbulance ahead!");\
}
int main(){
if (((block), t%2)) {
puts("nice 'n even");
}
else {
puts("odd..");
}
return 0;
}
Is the code valid c99/c1x? It compiles on clang and gcc without producing any errors, even when -Wall and -Wextra are set.

No. It's not valid under Standard C (C99/C11).
It's valid in GNU C, an extension as called statement expressions.

if (((block), t%2))
This evaluates to a statement expression followed by a comma operator. The return value of a block expression is the value of the last statement in the block. Comma operator evaluates from left to right and its value is equal to the last expression. If you try the -E option in gcc, you will get the preprocessed code, which looks like this:
if ((({ int temp = 1; t = time(((void *)0)); if (t == (time_t) -1 && temp) puts("turbulance ahead!");}), t%2))
So the condition in if statement is solely determined by the value of t%2(as per comma operator).
Is the code valid c99/c1x?
No. C99 generates warning for statement expressions.

It compiles on clang and gcc
No it doesn't. Compile it as the C language, not as the "GNU goo" language.
gcc file.c -std=c99 -pedantic-errors -Wall -Wextra

Related

Use of comma separated variables in foor loop [C] [duplicate]

This question already has answers here:
How does the Comma Operator work
(9 answers)
What does the comma operator , do?
(8 answers)
Closed 3 years ago.
In the linux kernel (ASOP) code I came across the following macro code:
#define for_each_cpu_and(cpu, mask, and) \
for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask, (void)and)
I have never come across a for loop like the one above where there are several comma separated variables along with the increment part. Using the following code I tried to check how the aforementioned macro actually behaves:
#include <stdio.h>
#include <stdbool.h>
#define for_each_cpu_and(cpu, mask, and) \
for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask, (void)and)
int main()
{
int i;
for_each_cpu_and(i, false, 3){
printf("i value: %d\n", i);
}
return 0;
}
The answer in the console is as follows:
i value: 0
If I tweek the code to the following:
#include <stdio.h>
#include <stdbool.h>
#define for_each_cpu_and(cpu, mask, and) \
for ((cpu) = 0; (cpu) < 3; (cpu)++, (void)mask, (cpu)+2)
int main()
{
int i;
for_each_cpu_and(i, 4, 3){
printf("i value: %d\n", i);
}
return 0;
}
The answer in the console is as follows:
i value: 0
i value: 1
i value: 2
So from the aformentioned code it seems like in the increment part only the first increment option i.e. (cpu)++ is given precedence and others are not being used.
Can someone please explain with example(s) the usage of additional comma separated variables in the increment part of the for loop?
Note: I am aware what a comma separated variable in C does in general and based on the rule the first varaible in the code should be given precedence. However, in the aforementioned code the case is not true. So explanation on the working of the comma separated variables in the increment part of the for-loop in the aforementioned code would be much appreciated.
Comma separated variables in C: How does the Comma Operator work

Preprocessor constant folding

I have a fundamental question regarding the C preprocessor constant evaluation and I would like some help in understanding if the preprocessor helps in optimizing the code in a situation like this. I understand that the preprocessor merely "replaces text" in the code. By that rule, even constant expressions get replaced in the code. For instance, the below code:
#include <stdio.h>
#define MY_NUM 2+2*2
int main()
{
int a = 6/MY_NUM;
printf("a: %d\n", a);
return 0;
}
The value of a comes to 7. This is because the preprocessed code looks something like this:
int main()
{
int a = 6/2+2*2;
printf("a: %d\n", a);
return 0;
}
I can see that MY_NUM did not evaluate to 6 before the compilation kicks in. Of course the compiler then optimizes the code by evaluating the value of a at compile time.
I am not sure if preprocessor constant folding happens or not or if it is even possible. Or is there any way (flag in gcc) to enable it. The regular -O optimizations do not enable this. Is there anyway we could change the behavior of the preprocessor here?
I am using gcc 4.8.4 for my code.
No, the only time the preprocessor evaluates any expression is in #if / #elif.
You can fake arithmetic by implementing it in terms of token concatenation and a ton of macros, but that's much harder than simply doing
#define MY_NUM (2+2*2)
But there's no simple compiler switch because macro expansion is just token replacement.

In C, why this statement- 'i = 5i' compiles & sets 'i' to zero?

In GCC the following C code compiles correctly-
int i = 7;
i = 5i;
printf("%d", i);
And prints- 0.
The statement i = 5i clearly makes no sense. Then why on earth the code does not give any compilation error? And why i becomes 0?
This is a GCC extension for representing the imaginary component of complex numbers.
The compiler complains if you compile with -pedantic and -Werror: http://ideone.com/PMlZr5.

Interpretation of instructions without effect

How can we interpret the following program and its success?(Its obvious that there must not be any error message). I mean how does compiler interpret lines 2 and 3 inside main?
#include <stdio.h>
int main()
{
int a,b;
a; //(2)
b; //(3)
return 0;
}
Your
a;
is just an expression statement. As always in C, the full expression in expression statement is evaluated and its result is immediately discarded.
For example, this
a = 2 + 3;
is an expression statement containing full expression a = 2 + 3. That expression evaluates to 5 and also has a side-effect of writing 5 into a. The result is evaluated and discarded.
Expression statement
a;
is treated in the same way, except that is has no side-effects. Since you forgot to initialize your variables, evaluation of the above expression can formally lead to undefined behavior.
Obviously, practical compilers will simply skip such expression statements entirely, since they have no observable behavior.
That's why you should use some compilation warning flags!
-Wall would trigger a "statement with no effect" warning.
If you want to see what the compilation produces, compile using -S.
Try it with your code, with/without -O (optimization) flag...
This is just like you try something like this:
#include <stdio.h>
int main(void){
1;
2;
return 0;
}
As we can see we have here two expressions followed by semicolon (1; and 2;). It is a well formed statement according to the rules of the language.
There is nothing wrong with it, it is just useless.
But if you try to use though statements (a or b) the behavior will be undefined.
Of course that, the compiler will interpret it as a statement with no effect
L.E:
If you run this:
#include <stdio.h>
int main(void){
int a;
int b;
printf("A = %d\n",a);
printf("B = %d\n",b);
if (a < b){
printf("TRUE");
}else{
printf("FALSE");
}
return 0;
}
You wil get:
A = 0
B = 0
FALSE
Because a and b are set to 0;
Sentences in C wich are not control structures (if, switch, for, while, do while) or control statements (break, continue, goto, return) are expressions.
Every expression has a resulting value.
An expression is evaluated for its side effects (change the value of an object, write a file, read volatile objects, and functions doing some of these things).
The final result of such an expression is always discarded.
For example, the function printf() returns an int value, that in general is not used. However this value is produced, and then discarded.
However the function printf() produces side effects, so it has to be processed.
If a sentence has no side effects, then the compiler is free to discard it at all.
I think that for a compiler will not be so hard to check if a sentence has not any side effects. So, what you can expect in this case is that the compiler will choose to do nothing.
Moreover, this will not affect the observable behaviour of the program, so there is no difference in what is obtained in the resulting execution of the program. However, of course, the program will run faster if any computation is ignored at all by the compiler.
Also, note that in some cases the floating point environment can set flags, which are considered side-effects.
The Standard C (C11) says, as part of paragraph 5.1.2.3p.4:
An actual implementation need not evaluate part of an expression if it
can deduce that its value is not used and that no needed side effects
are produced [...]
CONCLUSION: One has to read the documentation of the particular compiler that oneself is using.

variable 1 = ({statement 1;statement 2;}) construct in C

main()
{
int a=10,b=30,c=0;
if( c =({a+b;b-a;}))
{
printf("%d",c);
}
}
why the construct ({;}) is legal in C and why it returns the last statement value as the result of the expression ( why it work similar to comma operator)?
It is not legal standard C99, but it is a very useful GCC extension, called statement-exprs (a parenthesized brace compound statement ending by some expression).
IIRC, some other compilers support that extension, e.g. Clang/LLVM
Statement expressions are much more useful when they contain control flow changes and side-effects, like:
c = 2*({while (a>0) a--,b--; a+b;});
However, in your particular case, you could just use the comma operator
if (c=(a+b,b-a))
Since a+b does not have any side effect, I guess that an optimizing compiler could handle that as
if (c=b-a)
GCC provides other useful extensions, notably local labels using __label__ and label as values with computed gotos (very useful in threaded interpreters ...). I don't know exactly why they have not been standardized. I wish that they would.
main()
{
int a=10,b=30,c=0;
if( c =({a+b;b-a;}))
{
printf("%d",c);
}
}
Here,{a+b;b-a;} is one scope.In this you have written 2 statements.This is actually treated as
{
c=a+b;
c=b-a;
}
Initially c value is 40 because of a+b. Again c is modified by b-a. To prove this consider following three cases..
(1).
if(c=({(a=a+b);;}))
{
printf("%d\n",c);
printf("%d\n",a);
}
Here o/p is c=40 and a=40;Because at end of scope (i.e) in last statement is dummy (;).
so,c=a+b is o/p.
(2)
if(c=({(a=a+b);b-a;}))
{
printf("%d\n",c);
printf("%d\n",a);
}
Here o/p is c=-10, a=40. Because last statement is b-a. this value is assigned to c.
(3) main()
{
int a=10,b=30,c=0;
if(c=({(a=a+b);0;}))
{
printf("%d\n",c);
printf("%d\n",a);
}
printf("%d\n",c);
}
Here o/p is c=0 only.If is not executed ,Because of last statement is 0;
C follows procedure oriented.And associativity of () is left to right.

Resources