Compiler Version: Keil C51 5.0
I experienced some unexpected behaviour with the Keil C51 compiler. I have recreated the issue in the below code snippets.
Case 1: Result of bit shift operator is type casted from uchar (8b) to ulong (32b) correctly
unsigned long tempadcVal; unsigned char data_save_high = 0xA4; unsigned char data_save_low = 0x3F; //The expected 32b value without any information loss //Is loaded into tempadcVal tempadcVal = (data_save_high<<2) + (data_save_low>>6);
Case 2: Result of bit shift operator is not type casted from uint (16b) to ulong (32)
unsigned long modulated; unsigned int value = 0xA43F; modulated = value<<8; //Here we have modulated = 0x00003F00 (Wrong!) //Top 8 bits are wiped out
Is this behaviour by design or perhaps a mistake in the compiler?
So, Bob McNamara, are you saying that the standard C behaviour is for int to be the special 'default case' data type and variables are typecasted by default to the int data type only?
No. That is not what I was trying to say at all, nor is that what is happening. There are rules for what types are used for arithmetic operations. The types of the operands will be the same and any "lower type" will be converted to the "higher type"
712 If both operands have the same type, then no further conversion is needed.
713 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.
714 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.
715 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.
716 Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type.
unsigned long tempadcVal; unsigned char data_save_high = 0xA4; unsigned char data_save_low = 0x3F; //The expected 32b value without any information loss //Is loaded into tempadcVal tempadcVal = (data_save_high<<2) + (data_save_low>>6); //***** "<<" is an arithmetic operator. //***** data_save_high is an unsigned character //***** 2 is an integer //***** data_save_high must be converted to an integer before the arithmetic operation is performed ( 713 above) //** the value of data_save_high is typecast to an int and then shifted (2 is an int) //** the value of data_save_low is typecast to an int and then shifted ( 6 is an int) //** both ints are added together and the resulting int is typecast to an unsigned long
Case 2: Result of bit shift operator is not typecast from uint (16b) to ulong (32)
unsigned long modulated; unsigned int value = 0xA43F; modulated = value<<8; //***** value is not typecast at all since it will not fit in an int //***** 8 is an integer and will be cast to an unsigned int //***** the << operator is acting on 2 unsigned int's (16-bits) //***** when you shift the 16-bits 8 bits to the left, you get 0x3F00 //***** After this is done, you then you assign the unsigned int to an unsigned long int, but you have already lost the upper 16-bits. //** when shifted value == 0x3F00 (as I believe it should be) //** unsigned int result is typecast to an unsigned long at this point. (0x00003F00)
//Here we have modulated = 0x00003F00 (Wrong!) //Top 8 bits are wiped out Is this behaviour by design or perhaps a mistake in the compiler?
Thank you, Bob McNamara, for the explanation. Now I think, I correctly understand the results of the above operations. Thanks, once again for clearing that up. -Ishank