I have below C code in which I have applied a not operator on a long double variable:
#include <stdio.h>
int main()
{
long double a;
signed char b;
int arr[sizeof(!a+b)];
printf("\n%d",sizeof(arr));
return 0;
}
This code outputs 16. I have problem in understanding what happenes when we apply not operator on long double, as we have done with a.
Please help me to understand whats happeneing with this code.
Thank You!
From the C Standard (6.5.3.3 Unary arithmetic operators)
5 The result of the logical negation operator ! is 0 if the value of
its operand compares unequal to 0, 1 if the value of its operand
compares equal to 0. The result has type int. The expression !E is
equivalent to (0==E).
So in this expression
sizeof(!a+b)
the sub-expression !a has the type int.
There are used the integer promotions of the operand b to the type int in the expression!a + b because the rank of the type signed char is less than the rank of the type int and the type int can represent all values of the type signed char.
From the C Standard (6.3.1.1 Boolean, characters, and integers)
...If an int can represent all values of the original type (as restricted
by the width, for a bit-field), the value is converted to an int;
otherwise, it is converted to an unsigned int. These are called the
integer promotions. 58) All other types are unchanged by the integer
promotions.
So the full expression is equivalent to
sizeof( int )
If the sizeof( int ) is equal to 4 then you have an array declared like
int arr[4];
Its size is equal to 16 that is to 4 * sizeof( int ).
Related
In the C language, with this code snippet:
uint16_t a = 243;
uint16_t b = 65535;
uint16_t max = 65535;
if ((a + b) > max)
{
printf("Out of range!");
}
else
{
printf("Within range.");
}
The result will be "Out of range!". What type conversion rules apply in this case? Can someone point me to a documented source?
Thanks!
If int is wider than 17 bits, a, b, and max will be converted to int. a + b will not overflow and will yield a result greater than max.
If int is 17 bits wide, a, b, and max will be converted to int. a + b will overflow, and the behavior is not defined by the C standard.
If int is 16 bits wide, a, b, and max will not be converted. a + b will wrap and will yield a result less than max.
From the C Standard (6.5.6 Additive operators)
4 If both operands have arithmetic type, the usual arithmetic
conversions are performed on them.
and (6.5.8 Relational operators)
3 If both of the operands have arithmetic type, the usual arithmetic
conversions are performed.
and at last (6.3.1.8 Usual arithmetic conversions)
... Otherwise, the integer promotions are performed on both operands.
and (6.3.1.1 Boolean, characters, and integers)
2 The following may be used in an expression wherever an int or
unsigned int may be used:
— An object or expression with an integer type (other than int or
unsigned int) whose integer conversion rank is less than or equal to
the rank of int and unsigned int.
— A bit-field of type _Bool, int, signed int, or unsigned int.
If an int can represent all values of the original type (as restricted
by the width, for a bit-field), the value is converted to an int;
otherwise, it is converted to an unsigned int. These are called the
integer promotions. 58) All other types are unchanged by the integer
promotions.
So in the condition of the if statement
if ((a + b) > max)
all operands are converted to the type int according to the integer promotions. And an object of the type int is able to store the value of the integer expression a + b where each operand is in turn converted to the type int.
In fact the above if statement you may imagine the following way
if ( ( ( int )a + ( int )b ) > ( int )max )
or like
if ( ( ( unsigned int )a + ( unsigned int )b ) > ( unsigned int )max )
depending on whether the type int or unsigned int can store the values of the type uint16_t.
An overflow can occur if for example the size of the type int or unsigned int is the same as the size of the type uint16_t.
I'm confused by the issue stated in the title. I've been told that in expressions involving both types of variables, signed are converted to/interpreted as unsigned. However, as the following code snippet shows, that isn't always the case.
Code:
unsigned int x = 1;
int y = -20;
printf("Right shift = %x, %d\n", y>>x, y>>x);
printf("If = %x, %d\n", y < x, y < x);
Result:
Right shift = fffffff6, -10
If = 0, 0
The if statement returns the expected 0, -20 being cast to a very large unsigned integer, but the shift expression returns -10, making it evident that arithmetic and not logical shift has taken place. The x has been interpreted as signed rather than the y being interpreted as unsigned.
Could anyone clear this up for me?
In this expression
y>>x
(the C Standard, 6.5.7 Bitwise shift operators)
3 The integer promotions are performed on each of the operands.
That means that as y has the type int and x has the type unsigned int neither conversion (promotion) occurs. And
...The type of the result is that of the promoted left operand.
So the result of the expression has the type int - the type of the operand y. As y has a negative value then
...IfE1 has a signed type and a negative value, the resulting value is
implementation-defined
As for this expression
y < x
then there is used the usual arithmetic conversions. The boths operands have the same rank so the operand y of the type int is converted to the type unsigned int and its binary representation as an object of the type unsigned int is greater than the binary representation of the operand x.
From the C Standard *6.3.1.8 Usual arithmetic conversions)
Otherwise, if the operand that has unsigned integer type has rank
greater or equal to the rank of the type of the other operand, then
the operand with signed integer type is converted to the type of the
operand with unsigned integer type.
I don't understand why the variable have value of 0, it should be 23?
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int array[] = {23, 34, 12, 17, 204, 99, 16};
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
int main(){
int d = -1, x = 0;
if (d <= TOTAL_ELEMENTS - 2)
x = array[d + 1];
printf("x= %d \n", x);
return 0;
}
This is due to the usual arithmetic conversions.
When the operands of a operator involve both a signed integer and an unsigned integer, and the unsigned type is at least as large as the signed type, the signed value is converted to an unsigned value. When the signed value is negative, it gets converted to a large positive value.
The rules for integer conversions are spelled out in section 6.3.1.8p1 of the C standard:
If both operands have the same type, then no further conversion is
needed.
Otherwise, if both operands have signed integer types or both have
unsigned integer types, the operand with the type of lesser
integer conversion rank is converted to the type of the operand
with greater rank.
Otherwise, if the operand that has unsigned integer type has
rank greater or equal to the rank of the type of the other
operand, then the operand with signed integer type is
converted to the type of the operand with unsigned integer
type.
Otherwise, if the type of the operand with signed integer type can
represent all of the values of the type of the operand with unsigned
integer type, then the operand with unsigned integer type is
converted to the type of the operand with signed integer type.
Otherwise, both operands are converted to the unsigned
integer type corresponding to the type of the operand with signed
integer type
In this expression:
(d <= TOTAL_ELEMENTS - 2)
Which expands to:
(d <= (sizeof(array) / sizeof(array[0])) - 2)
The sizeof operator evaluates to a value of type size_t which is unsigned. So the types of the operands look like this:
(int <= ((size_t / size_t) - int)
Both operands of the / operator are of type size_t so the result of that operation is of type size_t. Then the right operand of - is converted to type size_t. Since the value 2 fits in that type the value doesn't change.
Now we have the <= operator with an int on one size and a size_t on the other. The left operand is converted from int to size_t, however the value -1 doesn't fit in that type so it is converted. The converted value is actually the largest possible value for a size_t which is therefore greater than the value on the right side, making the result of <= false.
To fix this, you'll want to cast the unsigned value on the right to signed to prevent the left side from being converted:
if (d <= (int)(TOTAL_ELEMENTS - 2))
This question already has answers here:
Why is −1 > sizeof(int)?
(4 answers)
Closed 6 years ago.
The following program compiles successfully but when i ran it ,it prints nothing when i initialize the for loop with -1 but when i initialize for loop with 0 it successfully traverse all the array.I want to ask that can we don't traverse the array when we initialize the for loop with negative value??
#include <stdio.h>
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
int array[] = {23, 34, 12, 17, 204, 99, 16};
int main(void) {
int d;
//printf("%d",TOTAL_ELEMENTS);
for (d = -1; d <= (TOTAL_ELEMENTS - 2); d++)
{
printf("%d ",d);
printf("%d\n", array[d+1]);
}
return 0;
}
The result of sizeof operator is of type size_t, which is an unsigned type.
As a result, the type of TOTAL_ELEMENTS is also unsigned. When -1 is compared with it, it's converted to a big unsigned number. That's why d <= (TOTAL_ELEMENTS - 2) is false.
Here d <= (TOTAL_ELEMENTS - 2) operands are subject of usual arithmetic conversions (6.3.1.8). And actually integer promotions rules act in your case:
If both operands have the same type, then no further conversion is
needed.
Otherwise, if both operands have signed integer types or both
have unsigned integer types, the operand with the type of lesser
integer conversion rank is converted to the type of the operand with
greater rank.
Otherwise, if the operand that has unsigned integer type
has rank greater or equal to the rank of the type of the other
operand, then the operand with signed integer type is converted to the
type of the operand with unsigned integer type.
Otherwise, if the type
of the operand with signed integer type can represent all of the
values of the type of the operand with unsigned integer type, then the
operand with unsigned integer type is converted to the type of the
operand with signed integer type.
Otherwise, both operands are
converted to the unsigned integer type corresponding to the type of
the operand with signed integer type.
According to what you've got your code falls into clause #3, then your signed -1 is converted via rule (6.3.1.3):
Otherwise, if the new type is unsigned, the value is converted by
repeatedly adding or subtracting one more than the maximum value that
can be represented in the new type until the value is in the range of
the new type.
As result it becomes a very large unsigned value, that is surely greater than TOTAL_ELEMENTS - 2 and you'll never enter the loop.
This doesn't do what you think it does:
d <= (TOTAL_ELEMENTS - 2)
Instead, do this:
d <= int(TOTAL_ELEMENTS - 2)
Otherwise you've got a signed-vs-unsigned comparison, and your -1 becomes the largest possible size_t.
sizeof produces a result of size_t, which is unsigned. Compare a signed and unsigned type and you can only expect things to blow up.
To elaborate, when you try to use both signed and unsigned type in arithmatic operations, the signed type will be promoted to unsigned type, producing a huge number. Thus, the value of d , promoted to unsigned type, will fail to meet the condition d <= (TOTAL_ELEMENTS - 2);, hence the loop body will not execute.
For operators that expect operands of arithmetic type cause conversions. This pattern is called the usual arithmetic conversions. for this particular case, quoting the standard, chapter §6.3.1.8
Otherwise, the integer promotions are performed on both operands. Then the
following rules are applied to the promoted operands:
[...]
Otherwise, if the operand that has unsigned integer type has rank greater or
equal to the rank of the type of the other operand, then the operand with
signed integer type is converted to the type of the operand with unsigned
integer type.
and, regarding the rank,
The rank of any unsigned integer type shall equal the rank of the corresponding
signed integer type, if any.
Also, for reference, quoting C11, chapter 7.19, (emphasis mine)
size_t
which is the unsigned integer type of the result of the sizeof operator;
Hint: Enable compiler warning and it will point to your mistake.
To my semi-surprise with Xcode compiling C (gnu11)
#include <stdio.h>
int main(int argc,char**argv)
{
short s = 1;
printf( "%zd %zd %zd\n", sizeof(s), sizeof(s*s), sizeof(s?s:s));
return 0;
}
Produces the output
2 4 4
I was expecting
2 2 2
or possibly
2 4 2
Why is this?
I recalled from K&R that any integer expression smaller than an int is promoted to int. I found this in Standard (C89):
3.2.1.1 Characters and integers
A char, a short int, or an int bit-field, or their signed or
unsigned varieties, or an object that has enumeration type, may be
used in an expression wherever an int or unsigned int may be used. If
an int can represent all values of the original type, the value is
converted to an int;
The surprise is s?s:s because all reference I could find say the resulting type is an lvalue but that's just C++. C treats it as an rvalue. As expected then, C++'s output is:
2 4 2
Even if the expression is an rvalue. An unexpected difference between C and C++.
This is because the latter two sizeof operands contain operators. In C, types narrower than int are promoted to int before the operation is performed. So s * s is an int multiplied with an int, yielding an int.
Similarly for short ? short : short getting promoted to int ? int : int.
According to C11§6.5.15/5:
If both the second and third operands have arithmetic type, the result type that would be determined by the usual arithmetic conversions, were they applied to those two operands, is the type of the result. [...]
In your case, the result is equal to sizeof(int) because the 'usual arithmetic conversions' promote the shorts to ints. Same as with sizeof(s*s).