Why this conditional expression has the size of a float? - c

I expect the output to be "short int" but the output is "float".
#include <stdio.h>
int main(void)
{
int x = 1;
short int i = 2;
float f = 3;
if (sizeof((x == 2) ? f : i) == sizeof(float))
printf("float\n");
else if (sizeof((x == 2) ? f : i) == sizeof(short int))
printf("short int\n");
}

You expect (x == 2) ? f : i to have a type based on the value of x. But that is not how the C type system operates. The conditional operator is an expression, and all* expressions in C have a fixed type at compile time. It is this type that sizeof operates on. The value of the expression will depend on the value of x, but the type depends on f and i alone.
In this case, the type is the determined by the usual arithmetic conversions, which nominate float as the type of the result, same as if you had written f + i, where the result would unsurprisingly be a float too.
(*) - VLA's produce exemptions to this rule, but your question is not about one, so it's irrelevant.

You are asking the compiler to compute the size of (x == 2) ? f : i and that expression is a float.
Remember that sizeof is a compile-time operator, and that the ?: ternary conditional operator will have as type something which is convertible from both the "then" and the "else" case.
For details, refer to some C reference and to the C11 standard n1570

Related

Casting to _Bool

Traditionally, Boolean values in C were represented with int or char. The new _Bool type makes intent clearer, but also has another interesting feature: it seems casting floating-point numbers to it, does not truncate toward zero, but compares with exact zero:
#include <stdio.h>
int main(int argc, char **argv) {
double a = 0.1;
int i = (int)a;
printf("%d\n", i);
_Bool b = (_Bool)a;
printf("%d\n", b);
return 0;
}
prints
0
1
So this is a semantic difference. And one I'm happy with; it duplicates the effect of using a floating-point number as a conditional.
Is this something that can be depended on across-the-board? Does the new C standard define the result of casting X to _Bool as identical to X ? 1 : 0 for all X for which that is a valid operation?
In the C Standard (6.3.1.2 Boolean type) there is written
1 When any scalar value is converted to _Bool, the result is 0 if the
value compares equal to 0; otherwise, the result is 1.
That is during conversion to the type _Bool the compiler does not try to represent the value (truncating toward zero or something else) of the operand of an expression with the casting operator as an integer. It only checks whether the value is equal or unequal to zero.
Actually this declaration
_Bool b = (_Bool)a;
is equivalent to
_Bool b = a;
It is entirely consistent, a non-zero value implicitly cast to _Bool is true. Since _Bool is a true Boolean type and not "faked", it can behave correctly. So:
_Bool b = (_Bool)a ;
is equivalent to:
_Bool b = (a == 0) ;
not:
_Bool b = ((int)a == 0) ;
In the end interpreting a float as Boolean is nonsense and ill-advised as is comparing it for equality to zero. If you want the semantic you expect, you must code it explicitly:
_Bool b = (_Bool)((int)a);
Semantically that is equivalent to :
_Bool b = (a < 1.0);
It is clearer and safer to use a Boolean expression than to force a value to Boolean with a cast.

What is the cause of the lvalue error in the below mentioned code?

#include <stdio.h>
int main(void){
int n = 0, y = 1;
y == 1 ? n = 0 : n = 1;
if (n)
printf("YES");
else
printf("NO");
return 0;
}
Can some one explain why does the line with the ternary operator give a lvalue error. I have a very abstract idea of what lvalue is. Let me give my abstraction, correct me if I am wrong. lvalue is typically the address or we can say the variable where we store a constant value and the value of a variable or a constant is a rvalue. But I don't understand why is there an lvalue error in the assignment part of the ternary operator which states n = 0 : n = 1. It would be really helpful if I could get a proper understanding of what is wrong with my code.
The ternary operator ?: has higher precedence the assignment operator =. So your expression parses as:
(y == 1 ? n = 0 : n) = 1;
This gives you an expression on the left side of the assignment that is not an lvalue and therefore not assignable.
The ternary operator evaluates to either the value of the second part or the value of the third part, and these values are what you want to assign to n, so you could instead write it as:
n = y == 1 ? 0 : 1;
Or you could invert the condition and get rid of the ternary entirely:
n = y != 1;
The reason is that the ternary operator has higher precedence than assignment. So the expression is parsed as if you'd written:
(y == 1 ? n = 0 : n) = 1;
This is not a valid assignment because the result of the conditional operator is an rvalue, not an lvalue, so you can't assign to it.
You can solve the problem by adding parentheses around the assignments.
y == 1 ? (n = 0) : (n = 1);
But since you're assigning to the same variable, the more normal way to write this would be:
n = y == 1 ? 0: 1;
You can also take advantage of the fact that the result of a comparison operator is a boolean, either 0 or 1, so you can write simply:
n = y != 1;

variable assignment in conditional after && (C) [duplicate]

This question already has answers here:
Is short-circuiting logical operators mandated? And evaluation order?
(7 answers)
Closed 5 years ago.
I am curious about the exact definition of the C standard about variable assignment within a conditional clause. Here is a small example:
int foo() {
...
}
int bar() {
...
}
int main () {
int a, b, x, y;
...
if ( (a = foo()) == x && (b = bar() == y ) {
...
}
...
}
A test with GCC revealed that if (a = foo()) != x, b = bar() will not be executed. On the one hand this behavior is optimal, as it will not waste any time with the calculation of bar(). On the other hand, though, the value of b is somewhat undefined, because it depends on the result of foo(), which actually has nothing to do with b.
I wonder if there is an explicit definition for such cases in the C standard and what the reasons for that definition would be. And finally, what is considered to be best practice for writing such code?
A test with GCC revealed that if (a = foo()) != x, b = bar() will not be executed.
Well, that's the property of the logical AND (&&) operator.
Quoting C11, chapter §6.5.13, emphasis mine
Unlike the bitwise binary & operator, the && operator guarantees left-to-right evaluation;
if the second operand is evaluated, there is a sequence point between the evaluations of
the first and second operands. If the first operand compares equal to 0, the second
operand is not evaluated.
That said, for the assignment of b, you're right, if the first operand is FALSE, the value of b remains indeterminate and any usage of the variable may lead to undefined behavior.
(One of the) The best practice, is to initialize local variables upon definition to avoid use of indeterminate value.
The operator && consists of short circuit evaluation: the second subexpression is only evaluated if its result is needed in order to determine the result of the whole expression.
In your example, in the expression:
(a = foo()) == x && (b = bar() == y)
if the first subexpression (a = foo()) == x is evaluated to false, the result of the expression above is also false regardless of the result that the subexpression (b = bar() == y) would produce.
Because of both short-circuit evaluation and the fact that (a = foo()) == x evaluates to false, the expression (b = bar() == y) is never evaluated.
It's very simple: the second (i.e. right hand) argument of && will not be evaluated if the first argument evaluates to 0.
So, (b = bar() == y ) will not be evaluated if (a = foo()) == x is 0.
The fact that this could leave b uninitialised - with potentially undefined results - is a touchstone for the fact that you ought not code this way.
You could use
if ((a = foo() == x) & (b = bar() == y))
if you want both sides to always be evaluated: & is not short-circuited. But beware of unexpected effects if the arguments can evaluate to something other than 0 or 1 (which they don't in this case).

sizeof of the conditional operator's value ?:

#include <stdio.h>
int main()
{ int x = 1;
short int i = 2;
float f = 3;
if(sizeof((x == 2) ? f : i) == sizeof(float))
printf("float\n");
else if (sizeof((x == 2) ? f : i) == sizeof(short int))
printf("short int\n");
}
Here the expression ((x == 2) ? f : i) evaluates to i which is of type short int.. size of short int =2 whereas sizeof float is 4 byts.output should be "short int" but i m getting output "float"
Here the expression ((x == 2) ? f : i) evaluates to i which is of type short int
This is not how usual arithmetic conversions work in C. The second and third operands of ? : are first converted to a common type, and that type is the type of the result of the expression. And also that type will not in any case be smaller than int, because of promotions.
This is all described in clause 6.3.1 Arithmetic operands of the C11 standard, which is slightly too long to cite here.
sizeof is a compile-time operator, so it cannot evaluate x==2. It evaluates the type of the ternary expression, which in this case is float, via a conversion to a common type (the second and third operands of the ternary expression must be of the same type, and the int gets converted to float.)

"comparison between signed and unsigned integer expressions" with only unsigned integers

This warning should not appear for this code should it?
#include <stdio.h>
int main(void) {
unsigned char x = 5;
unsigned char y = 4;
unsigned int z = 3;
puts((z >= x - y) ? "A" : "B");
return 0;
}
z is a different size but it is the same signedness. Is there something about integer conversions that I'm not aware about? Here's the gcc output:
$ gcc -o test test.c -Wsign-compare
test.c: In function ‘main’:
test.c:10:10: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
puts((z >= x - y) ? "A" : "B");
^
$ gcc --version
gcc (Debian 4.9.1-15) 4.9.1
If z is an unsigned char I do not get the error.
The issue is that additive operators perform the usual arithmetic conversions on arithmetic types which. In this case it results in the integer promotions being performed on the operands, which results in unsigned char being converted to int since signed int can represent all the values of the type of unsigned char.
A related thread Why must a short be converted to an int before arithmetic operations in C and C++? explains the rationale for promotions.
C has this concept called "Integer Promotion".
Basically it means that all maths is done in signed int unless you really insist otherwise, or it doesn't fit.
If I put in the implicit conversions, your example actually reads like this:
puts((z >= (int)x - (int)y) ? "A" : "B");
So, now you see the signed/unsigned mismatch.
Unfortunately, you can't safely correct this problem using casts alone. There are a few options:
puts((z >= (unsigned int)(x - y)) ? "A" : "B");
or
puts((z >= (unsigned int)x - (unsigned int)y) ? "A" : "B");
or
puts(((int)z >= x - y) ? "A" : "B");
But they all suffer from the same problem: what if y is larger than x, and what if z is larger than INTMAX (not that it will in the example)?
A properly correct solution might look like this:
puts((y > x || z >= (unsigned)(x - y)) ? "A" : "B")
In the end, unless you really need the extra bit, it usually best to avoid unsigned integers.

Resources