C operators result type - c

In C11 (n1570), there are some operators whose result types are clearly stated. For example, the result of && has type int.
But I haven't found the result type of other operators, like +. Is it specified somewhere in the standard?
I tried this program:
unsigned char usc = 254;
unsigned int usi = 4294967293;
signed char sic = 126;
long long unsigned llu = usc*2;
printf("%llu\n",llu);
llu = usi*2;
printf("%llu\n",llu);
llu = usc+usc;
printf("%llu\n",llu);
llu = usi+usi;
printf("%llu\n",llu);
llu = usc+4294967294;
printf("%llu\n",llu);
llu = usc+2147483646;
printf("%llu\n",llu);
llu = sic+4294967294;
printf("%llu\n",llu);
llu = sic+2147483646;
printf("%llu\n",llu);
Output:
508
4294967290
508
4294967290
4294967548
18446744071562068220
4294967420
18446744071562068092
I guess unsigned char gets promoted here, but unsigned int doesn't; result type of char + unsigned int seems to be unsigned int, and result type of char + int seems to be int.
But I'm not so sure.
Are these castings standard, or implementation-defined?

The rules are explicitly defined by the standard:
6.3.1.8 Usual arithmetic conversions
1 Many operators that expect operands of arithmetic type cause conversions and yield result
types in a similar way. The purpose is to determine a common real type for the operands
and result. For the specified operands, each operand is converted, without change of type
domain, to a type whose corresponding real type is the common real type. Unless
explicitly stated otherwise, the common real type is also the corresponding real type of
the result, whose type domain is the type domain of the operands if they are the same,
and complex otherwise. This pattern is called the usual arithmetic conversions:
First, if the corresponding real type of either operand is long double, the other
operand is converted, without change of type domain, to a type whose corresponding real type is long double.
Otherwise, if the corresponding real type of either operand is double, the other
operand is converted, without change of type domain, to a type whose
corresponding real type is double.
Otherwise, if the corresponding real type of either operand is float, the other
operand is converted, without change of type domain, to a type whose
corresponding real type is float.62)
Otherwise, the integer promotions are performed on both operands. Then the
following rules are applied to the promoted operands:
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.
Still, how big your types are and whether signed types use 1s-complement, 2s-complement or sign-and-magnitude representation is implementation-defined.
You properly deduced what happens for your implementation.

There is no “casting” in your examples, only conversions. A cast is a syntactic construct, like (unsigned long), that causes a conversion. Conversions also happen on their own, as they do in your examples.
The names for the conversions that happen in your examples is “usual arithmetic conversions”. They are described in the C11 standard at clause 6.3.1.8, which is too long to quote in full (it also handles the conversion from integer type to floating-point type when the program contains 1 + 1.0). For integer types, the rules look like:
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.
The type of the result is the same as the common type decided for the operands.
Frama-C's front-end, which is only one “apt-get install” away if you are using Linux, makes these conversions explicit and displays them as casts when you command it to print the Abstract Syntax Tree it has built. On your examples, the conversions are (removing the printf() calls that do not add information):
$ frama-c -print t.c
...
usc = (unsigned char)254;
usi = 4294967293;
sic = (signed char)126;
llu = (unsigned long long)((int)usc * 2);
llu = (unsigned long long)(usi * (unsigned int)2);
llu = (unsigned long long)((int)usc + (int)usc);
llu = (unsigned long long)(usi + usi);
llu = (unsigned long long)((unsigned int)usc + 4294967294);
llu = (unsigned long long)((int)usc + 2147483646);
llu = (unsigned long long)((unsigned int)sic + 4294967294);
llu = (unsigned long long)((int)sic + 2147483646);
This is for a common ILP32 architecture. Implementation-defined parameters can influence the conversions, as for instance the type of 40000 may be int for most C99 compilers and long int with others (it is always the first type in the list int, long int, long long int that can represent the constant).

Related

How does an unsigned integer and literal get compared in C?

I'm doing the following comparison:
uint32_t value = 1000;
if(value < 100)
{
// do something
}
What get's casted to what in this case? Does 'value' get casted to an integer? Does 100 get casted to an integer or unsigned integer?
First, all numeric constant have a type. In the case of the constant 100, because it is decimal, has no suffix, and can fit in the range of an int, the constant has type int.
How the comparison is performed is dictated by the usual arithmetic conversions. Specifically, the conversion rules for integer types are specified in section 6.3.1.8p1 of the C standard as follows:
... the integer promotions are performed on both operands.
Then the following rules are applied to the promoted operands:
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
Assuming an int on your platform is 32 bits, that makes uint32_t the same as an unsigned int, so you're using a signed type and an unsigned type of the same size in an expression. That being the case, the third bullet point above applies, namely the value 100 (which has type int) is converted to an unsigned int and then the values are compared.
In this case, the value 100 is also within the range of an unsigned int, so there is no conversion of the actual value. If it was instead something like -100, that value is not in the range of an unsigned int, which means the value would be converted to be within that range. Again, assuming a 32 bit int the value would be 232 - 100.
If two integer expressions have the same rank as in your example provided that the type uint32_t is an alias for the type unsigned int then the signed type is converted to the unsigned type. That is the integer literal 100 that has the type signed int is converted to the type unsigned int.
From the C Standard (6.3.1.1 Boolean, characters, and integers)
— The rank of any unsigned integer type shall equal the rank of the
corresponding signed integer type, if any.
And (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

Conversion to float in uint32_t calculation

I am trying to improve a SWRTC by modifying the definition of a second (long unsigned n_ticks_per_second) by synchronizing time with a server.
#include <stdint.h>
#include <stdio.h>
int main(int argc, char * argv[]){
int32_t total_drift_SEC;
int32_t drift_per_sec_TICK;
uint32_t at_update_posix_time = 1491265740;
uint32_t posix_time = 1491265680;
uint32_t last_update_posix_time = 1491251330;
long unsigned n_ticks_per_sec = 1000;
total_drift_SEC = (posix_time - at_update_posix_time);
drift_per_sec_TICK = ((float) total_drift_SEC) / (at_update_posix_time - last_update_posix_time);
n_ticks_per_sec += drift_per_sec_TICK;
printf("Total drift sec %d\r\n", total_drift_SEC);
printf("Drift per sec in ticks %d\r\n", drift_per_sec_TICK);
printf("n_ticks_per_second %lu\r\n", n_ticks_per_sec);
return 0;
}
What I don't understand is that I need to cast total_drift_SEC to float in order to have a correct result in the end, ie to have n_ticks_per_sec equal to 1000 in the end.
The output of this code is:
Total drift sec -60
Drift per sec in ticks 0
n_ticks_per_second 1000
Whereas the output of the code without the cast to float is:
Total drift sec -60
Drift per sec in ticks 298054
n_ticks_per_second 299054
This line
drift_per_sec_TICK = total_drift_SEC / (at_update_posix_time - last_update_posix_time);
divides a 32 bit signed int by a 32 bit unsigned int.
32 bit unsigned int has a higher rank then 32 bit signed int.
When doing arithmetic operations the "Usual Arithmetic Conversions" are applied:
From the C11 Standard (draft) 6.3.1.8/1:
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.
So -60 gets converted to a (32 bit) unsigned int: 4294967236
Here
drift_per_sec_TICK = (float) total_drift_SEC / (at_update_posix_time - last_update_posix_time);
The following applies (from the paragraph of the C Standard as above):
if the corresponding real type of either operand is float, the other
operand is converted, without change of type domain, to a type whose
corresponding real type is float.
To not blindly step into those traps always specify -Wconversion when compiling with GCC.
Because with "integer" version total_drift_SEC will become unsigned so -60 --> 4294967236
4294967236 / 14410 = 298054
Using float the division will calculate:
-60/14410 = 0
Referring to the c-standard at page 53
6.3.1.8 Usual arithmetic conversions
1 Many operators that expect operands of arithmetic type cause conversions and yield result
types in a similar way. The purpose is to determine a common real type for the operands
and result. For the specified operands, each operand is converted, without change of type
domain, to a type whose corresponding real type is the common real type. Unless
explicitly stated otherwise, the common real type is also the corresponding real type of
the result, whose type domain is the type domain of the operands if they are the same,
and complex otherwise. This pattern is called the usual arithmetic conversions:
[...]
Otherwise, the integer promotions are performed on both operands. Then the
following rules are applied to the promoted operands:
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.
Ephasis mine

Integer conversion rank of signed and unsigned int

For example, If I have,
int a = 42;
unsigned b = 10;
int c = a + b;
For this statement, int c = a + b; Would a be first converted to an unsigned int or would it be b that will be converted to a signed int? Both unsigned int and signed have the same conversion rank so how do we know which one will be converted? Is there a Standard rule?
Short answer: Per C99 6.3.1.8-p1, as value will be converted to an unsigned int by, per C99 6.3.1.3-p2, having UINT_MAX+1 added to it until it falls in the range allowed by unsigned int. Since it is already in that range, no addition will be performed. By C99 6.3.1.3-p3, the results assigned back to int c would be implementation defined if (p1) and (p2) didn't apply. But in this case note the "value" clause of 6.3.1.3-p1. The value (52) in this case can be represented by int, so it is not changed, and is defined.
C99 6.3.1.3 Signed and unsigned integers
When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.
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.60)
Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.
C99 6.3.1.8 Usual arithmetic conversions
Many operators that expect operands of arithmetic type cause conversions and yield result types in a similar way. The purpose is to determine a common real type for the operands and result. For the specified operands, each operand is converted, without change of type domain, to a type whose corresponding real type is the common real type. Unless explicitly stated otherwise, the common real type is also the corresponding real type of the result, whose type domain is the type domain of the operands if they are the same, and complex otherwise. This pattern is called the usual arithmetic conversions:
First, if the corresponding real type of either operand is long double, the other operand is converted, without change of type domain, to a type whose corresponding real type is long double.
Otherwise, if the corresponding real type of either operand is double, the other operand is converted, without change of type domain, to a type whose corresponding real type is double.
Otherwise, if the corresponding real type of either operand is float, the other operand is converted, without change of type domain, to a type whose corresponding real type is float.62)
Otherwise, the integer promotions are performed on both operands. Then the following rules are applied to the promoted operands:
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.

Why is the output wrong?

#include<stdio.h>
main()
{
unsigned x=1;
signed char y=-1;
clrscr();
if(x>y)
printf("x>y");
else
printf("x<=y");
}
A signed character has an increased value from -128 to 127. So the expected out put should have been 'x>y', but it isn't. The compiler gives the output - "x<=y". Can you explain why?
In the comparison the signed char gets converted to an unsigned int and thus looks like a really big value. I would expect the compiler to warn you - i.e. something in the lines "comparing signed and unsigned stuff is confusing".
This conversion is mandated under "Relational operators":
If both of the operands have arithmetic type, the usual
arithmetic conversions are performed.
C11 §6.8 al3 p95 :
If both of the operands have arithmetic type, the usual arithmetic conversions are
performed.
C11 §6.3.1.8 al1 p53 :
[...] 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.
So y will be promote to an unsigned type, and will be greater than x (1).
in comparison, if one operand is unsigned, then the other operand is implicitly converted into unsigned if its type is signed!
more to found here : Signed/unsigned comparisons
In your case signed char is converted to unsigned int, thus we are getting a big positive integer instead of -1. Here is an extract from ANSI C standard draft that explains what happens during usual arithmetic conversions that took place.
3.2.1.5 Usual arithmetic conversions
Many binary operators that expect operands of arithmetic type cause
conversions and yield result types in a similar way. The purpose is
to yield a common type, which is also the type of the result. This
pattern is called the usual arithmetic conversions: First, if either
operand has type long double, the other operand is converted to long
double . Otherwise, if either operand has type double, the other
operand is converted to double. Otherwise, if either operand has type
float, the other operand is converted to float. Otherwise, the
integral promotions are performed on both operands. Then the
following rules are applied: If either operand has type unsigned long
int, the other operand is converted to unsigned long int. Otherwise,
if one operand has type long int and the other has type unsigned int,
if a long int can represent all values of an unsigned int, the operand
of type unsigned int is converted to long int ; if a long int cannot
represent all the values of an unsigned int, both operands are
converted to unsigned long int. Otherwise, if either operand has type
long int, the other operand is converted to long int.
Otherwise, if either operand has type unsigned int, the other operand is converted to unsigned int. Otherwise, both operands have
type int.
Get used to compile with all warnings, i.e. in the case of gcc:
gcc -Wall -Wextra -pedantic source.c -o prog
In your case the flag -Wextra give the following message:
warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
That doesn't explain why, but it warns you at least ;) .
The explanation is that a signed variable evaluating to -1 is equal to an unsigned evaluating to UINT_MAX when compared with a relational operator.
The compiler has to do something well defined in that case and this is what people came up with...
When the compiler see comparing an unsigned int with signed int it promote the signed int to unsigned, this mean adding this (in linux box) to the signed one:
#define UINT_MAX (~0U) (defined in this header file : /include/linux/kernel.h)
So now you are comparing UINT_MAX - 1 (UINT_MAX + y) with x, which explain clearly the output.
Edit : to be more clear : on 32 bits machine ---> UINT_MAX = 2 147 483 648 = 2**31
Regards.

In a C expression where unsigned int and signed int are present, which type will be promoted to what type?

I have a query about data type promotion rules in C language standard.
The C99 says that:
C integer promotions also require that "if an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int."
My questions is in case of a C language expression where unsigned int and signed int are present, which type will be promoted to what type?
E.g. int cannot represent all the values of the unsigned int (values larger than MAX_INT values) whereas unsigned int cannot represent the -ve values, so what type is promoted to what in such cases?
I think you are confusing two things. Promotion is the process by which values of integer type "smaller" that int/unsigned int are converted either to int or unsigned int. The rules are expressed somewhat strangely (mostly for the benefit of handling adequately char) but ensure that value and sign are conserved.
Then there is the different concept of usual arithmetic conversion by which operands of arithmetic operators are converted to a common type. It begins by promoting the operand (to either int or unsigned) if they are of a type smaller than int and then choosing a target type by the following process (for integer types, 6.3.1.8/1)
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.
(Note that ISTR that those rules have changed slightly between C89 and C99)
I think the following answers your question:
6.3.1.3 Signed and unsigned integers
1 When a value with integer type is
converted to another integer type
other than _Bool, if the value can be
represented by the new type, it is
unchanged.
2 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.
3 Otherwise,
the new type is signed and the value
cannot be represented in it; either
the result is implementation-defined
or an implementation-defined signal is
raised.

Resources