I have a doubt from the below 2 code snippets.
I ran this code on 64-bit machine (x86_64-linux-gnu). I can see the value Val overflows when the data type is unsigned integer.
#include<stdio.h>
main()
{
unsigned int Val = 0xFFFFFFFF-15, Val2 = 0xFFFFFFFF;
if (Val+16 < Val2)
{
printf("Val is less than Val2\n");
}
}
If the data type is unsigned char it does not overflow.
#include<stdio.h>
main()
{
unsigned char Val = 0xFF-15, Val2 = 0xFF;
if (Val+16 < Val2)
{
printf("Val is less than Val2\n");
}
}
I have two questions:
Does the value Val get promoted to high data type when the data type is unsigned char?
If yes, why did not it get promoted from 32-bit to 64-bit unsigned long?
The C11 standard says the following (C11 6.3.11p2.2):
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. All other types are unchanged by the integer promotions.
Thus:
unsigned char will be promoted - however it is an implementation detail whether int can represent all values of unsigned char - so it might be promoted to an unsigned int on those platforms. Yours is not one of those platforms, thus your second comparison is (int)Val + 16 < (int)Val2.
as the last sentence of the quoted paragraph tells, an unsigned int is never promoted. Since the arithmetic is done on unsigned ints in the first fragment, the result of 0xFFFFFFFF - 15 + 16 is 0U on a computer with 32-value-bit unsigned int.
Yes, in the second case the numbers are promoted to int. If you modify your code thus:
#include<stdio.h>
int main()
{
unsigned char Val = 0xFF-15, Val2 = 0xFF;
if ((unsigned char)(Val+16) < Val2)
{
printf("Val is less than Val2\n");
}
}
You will get the behaviour you expect.
Related
I have a problem. In this program the variable x should be set to 0x10000 but in both operations the result is 0.
This is not the main program but a test to find the reason for the error. I am currently making a 64 bit multiplier with hex input. I used 16-bit multiplication using Keil and Proteus
int main() {
unsigned long int x = 0;
x = 0x8000 * 0x2;
x = 0x8000 + 0x8000;
return 0;
}
The literal 0x8000 is of type unsigned int. On your 16-bit machine, the int and therefore unsigned int is of the natural size of 16 bits, the smallest accepted by the C standard. The integer promotion rules say that the smaller width types are widened to int or unsigned int, but no further (C11 n1570 6.3.1.1p2):
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.
An operand is widened from int or unsigned int only if the other operand has a greater rank.
Here, 0x8000 + 0x8000 is calculated using unsigned int which will wrap to 0, because the maximum value that can be represented in unsigned int is 0xFFFF.
You should force at least one of the operands to unsigned long using either the suffix UL, or by adding an explicit cast:
int main() {
unsigned long int x=0;
/* unsigned long int * int */
x = 0x8000UL * 0x2;
/* unsigned long + unsigned int */
x = (unsigned long)0x8000 + 0x8000;
return 0;
}
See also In a C expression where unsigned int and signed int are present, which type will be promoted to what type? for general discussion.
It is not clear way (or that) the variable x should be 0x10000. x is a unsigned long int, but the values you assign to it are unsigned int. And if on that platform int is only 16 bit, both 0x8000 * 2 and 0x8000 + 0x8000 are 0.
Try using 0x8000L (or better 0x8000UL) for creating long literals at the first place.
I'm new to C and have seen code such as (unsigned)b
Does that imply that b will be an unsigned int? Or what type does it imply?
b will be whatever type it was to begin with. That doesn't change
(unsigned)b will evaluate as whatever value b is, but that is subject to the cast to unsigned, which is synonymous with unsigned int.
How that happens depends entirely on the type of b to begin with, whether that type is convertible to unsigned int, and whether the value contained therein falls unscathed between 0...UINT_MAX or not.
Ex:
#include <stdio.h>
void foo(unsigned int x)
{
printf("%u\n", x);
}
int main()
{
int b = 100;
foo((unsigned)b); // will print 100
char c = 'a';
foo((unsigned)c); // will print 97 (assuming ASCII)
short s = -10; // will print 4294967286 for 32-bit int types
// (see below for why)
foo((unsigned)s);
// won't compile, not convertible
//struct X { int val; } x;
//foo((unsigned)x);
}
The only part of this that may raise your eye brow is the third example. When a value of a convertible type to an unsigned type is out of the unsigned type's range (ex: negative values are not same-value representable with any unsigned target types), the value is converted by repeatedly added the maximum value representable by the unsigned target plus-one to the out-of-range value until such time as it falls within the valid range of the unsigned type.
In other words, because -10 is not within the valid representation of unsigned int, UINT_MAX+1 is added to -10 repeatedly (only takes once in this case) until the result is within 0...UINT_MAX.
Hope that helps.
unsigned is a short of unsigned int
signed is a short of signed int
long is the short of long int
long long is the short of long long int
short is the short of short int
Suppose the following:
unsigned char foo = 3;
unsigned char bar = 5;
unsigned int shmoo = foo + bar;
Are foo and bar values guaranteed to be promoted to int values for the evaluation of the expression foo + bar -- or are implementations allowed to promote them to unsigned int?
In section 6.2.5 paragraph 8:
For any two integer types with the same signedness and different integer conversion rank
(see 6.3.1.1), the range of values of the type with smaller integer conversion rank is a
subrange of the values of the other type.
In section 6.2.5 paragraph 9:
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.
The guarantee that an integer type with smaller integer conversion rank has a range of values that is a subrange of the values of the other type seems dependent on the signedness of the integer type.
signed char corresponds to signed int
unsigned char corresponds to unsigned int
Does this mean that the value of an unsigned char is only guaranteed to be in the subrange of unsigned int and not necessarily int? If so, does that imply that an implementation could theoretically have an unsigned char value which is not in the subrange of an int?
are implementations allowed to promote them to unsigned int?
Implementations will promote to unsigned int if not all unsigned char values are representable in an int (as ruled by 6.2.5p9 in C99). See below for implementation examples.
If so, does that imply that an implementation could theoretically have an unsigned char value which is not in the subrange of an int?
Yes, example: DSP cpu with CHAR_BIT 16 or 32.
For example, TI C compiler for TMS320C55x: CHAR_BIT is 16 and UCHAR_MAX 65535, UINT_MAX 65535 but INT_MAX 32767.
http://focus.ti.com/lit/ug/spru281f/spru281f.pdf
I ran across this yesterday - hope that my answer is on topic.
uint8_t x = 10;
uint8_t y = 250;
if (x - y > 0) {
// never happens
}
if (x - y < 0U) {
// always happens
}
To my eyes at least it was appearing as though values x and y were being unexpectedly promoted, when in fact is was their result that was promoted.
This question already has answers here:
Comparison operation on unsigned and signed integers
(7 answers)
Closed 4 years ago.
int main(void)
{
unsigned int y = 10;
int x = – 4;
if (x > y)
Printf("x is greater");
else
Printf("y is greater");
getch();
return (0);
}
Output: x is greater
I thought the output would be y is greater since it is unsigned. What's the reason behind this?
Because the int value is promoted to an unsigned int. specifically 0xFFFFFFFC on a 32-bit machine, which as an unsigned int is 4294967292, considerably larger than 10
C99 6.3.1.1-p2
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. All other types are unchanged by the integer promotions.
To perform the conversion:
C99 6.3.1.3-p2
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.
Which basically means "add UINT_MAX+1" (as I read it, anyway).
Regarding why the promotion was to the unsigned int side; precedence:
C99 6.3.1.8-p1
...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.
Which tells me int vs. unsigned char should work as expected.
Test
int main()
{
int x = -4;
unsigned int y = 10;
unsigned char z = 10;
if (x > y)
printf("x>y\n");
else
printf("x<y\n");
if (x > z)
printf("x>z\n");
else
printf("x<z\n");
return 0;
}
Output
x>y
x<z
Well look at that.
A comparison between a signed and an unsigned value will be made in "unsigned space". I.e., the signed value will be converted to unsigned by adding UINT_MAX + 1. In implementation using the 2-complement for negative values, no special handling of the values is required under the hood.
In this example, the -4 is turned into a 0x100000000-4 = 0xFFFFFFFC which is clearly > 10.
When you compare two values in C, they both must be of the same type. In this case (int and unsigned int) the int value will be converted to an unsigned int first.
Second, unsigned integer arithmetic in C is done modulo the maximum value of that type + 1 (that is, it "loops around" so UINT_MAX + 1 is 0 again and vice versa). Therefore converting negative values to unsigned results in very large numbers.
The relevant section in the standard says:
6.3.1.3 Signed and unsigned integers
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.
When you compare an int and an unsigned int the int is converted to unsigned int.
The convertion of an int to an unsigned int is done by adding UINT_MAX+1 (note that your int is negative). So actually you are comparing:
if (-3 + UINT_MAX > 10) //Since -4 is converted to UINT_MAX+1-4
Which is true.
The first bit of an int value is used to define if it's a positive or a negative one. (1 = negative, 0 positive)
Your both variable are cast into unsigned int before comparison where the 1 in the first bit will be interpreted as part of your number.
this code should work fine :
int main(void)
{
unsigned int y = 10;
int x = – 4;
if (x > (int) y)
Printf("x is greater");
else
Printf ("y is greater");
getch ( );
return (0);
}
int x=-4 (2's complement of 4 is 1111 1100 =252) and unsigned int y=10 is(0000 1010 =10) so 252 >10 so -4 is greater than 10.
When I multiply two unsigned chars in C like this:
unsigned char a = 200;
unsigned char b = 200;
unsigned char c = a * b;
Then I know I will have an overflow, and I get (40'000 modulo 256) as a result. When I do this:
unsigned char a = 200;
unsigned char b = 200;
unsigned int c = (int)a * (int)b;
I will get the correct result 40'000. However, I do not know what happens with this:
unsigned char a = 200;
unsigned char b = 200;
unsigned int c = a * b;
Can I be sure the right thing happens? Is this compiler dependent? Similarly, I don't know what happens when doing a subtraction:
unsigned char a = 1;
unsigned char b = 2;
int c = a - b;
When making "c" an unsigned char, I will probably get 255 as a result. What happens when I use an int like this?
Argument of arithmetic operators get the "usual arithmetic promotions".
In cases where int can represent all the values of all the operands (at it is the case for your example in most implementations), arguments are first converted to int. So in both cases, you get the correct result.
Copied from this answer In a C expression where unsigned int and signed int are present, which type will be promoted to what type?
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.