473,394 Members | 1,870 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,394 software developers and data experts.

A problem about type cast in bitwise shift

Hi,folks.
I got some suggestion about bitwise shift from <The C Book, second
edition>(written by Mike Banahan, Declan Brady and Mark Doran,
originally published by Addison Wesley in 1991. This version is made
freely available at http://publications.gbdirect.co.uk/c_book/)
....snip...
The position is clearer if an unsigned operand is right shifted,
because there is no choice: it must be a logical shift. For that
reason, whenever right shift is being used, you would expect to find
that the thing being shifted had been declared to be unsigned, or cast
to unsigned for the shift, as in the example:
int i,j;
i = (unsigned)j >> 4;
....snip...
However, when I run the following program with some little changes,
the result confused me.
statement 1:
the printed results of variables m and n are different.
replacing statement 1 with statement 2:
the same as above.
replacing statement 1 with statement 3:
the printed results of variables m and n are the same, which is what I
expected.
So, I'am sure the statements 1 and 2 are incorrect.
The variables i and n both have the type of unsigned char,
is the type of "n<<i"unsigned char?If so, is the type cast necessary?
or, if not, is that the reason of integer promotion?
What about statement 2 comparing to statemnt 1?
IMHO, they are the same.
Any comments are appreciated in advance.
/**************bitwise_shift.c**************/
#include <stdio.h>

int main(void)
{
unsigned char c = 0x79;
unsigned char m;
unsigned char n;
unsigned char i = 2;

printf("sizeof(unsigned char) = %u\n", sizeof(unsigned char));
m = c;
m <<= i;
m >>= 7U;
printf("m = %c\n", m);
n = c;
n = (n << i) >> 7U; /*statement 1*/
/*n = (n << 2U) >> 7U;*/ /*statement 2*/
/* n = (unsigned char)(n << i) >> 7;*/ /*statement 3*/
printf("n = %c\n", n);

return 0;
}
/***************end of bitwise_shift***************/

Feb 22 '06 #1
4 5124
kernelxu wrote:
....snip...
However, when I run the following program with some little changes,
the result confused me.
statement 1:
the printed results of variables m and n are different.
replacing statement 1 with statement 2:
the same as above.
replacing statement 1 with statement 3:
the printed results of variables m and n are the same, which is what I
expected.
So, I'am sure the statements 1 and 2 are incorrect.
The variables i and n both have the type of unsigned char,
is the type of "n<<i"unsigned char?If so, is the type cast necessary?
or, if not, is that the reason of integer promotion?
What about statement 2 comparing to statemnt 1?
IMHO, they are the same.
Any comments are appreciated in advance.
/**************bitwise_shift.c**************/
#include <stdio.h>

int main(void)
{
unsigned char c = 0x79;
unsigned char m;
unsigned char n;
unsigned char i = 2;

printf("sizeof(unsigned char) = %u\n", sizeof(unsigned char));
m = c;
/* Statement 0 */
m <<= i;
m >>= 7U;
printf("m = %c\n", m);
n = c;
n = (n << i) >> 7U; /*statement 1*/
/*n = (n << 2U) >> 7U;*/ /*statement 2*/
/* n = (unsigned char)(n << i) >> 7;*/ /*statement 3*/
printf("n = %c\n", n);

return 0;
}
/***************end of bitwise_shift***************/


As you have guessed correctly, the reason for the different values is
integral promotion.

In statement 0 the type of the operands are promoted to int (which can
at least store 15 bit unsigned number).
The result of shifting 0x79 by 2 is 0x1E4, but when you store the value
into m, only the modulo 256 of the value is stored back (ie. 0xE4) due
to implicit typecast to unsigned char. The value 0xE4 is then shifted
right by 7 which gives 1 as result.

Whereas in statement 1, the value 0x1E4 is shifted right by 7 without
truncation which gives 3 as a result.

And there is no difference between statement 1 and 2.

In statement 3, the value 0x1E4 is typecasted to unsigned char which
results in 0xE4 and then shifted right by 7 which is same as the
statement 0.

Feb 22 '06 #2

suresh wrote:
/* Statement 0 */
m <<= i;
m >>= 7U;
printf("m = %c\n", m);
n = c;
n = (n << i) >> 7U; /*statement 1*/
/*n = (n << 2U) >> 7U;*/ /*statement 2*/
/* n = (unsigned char)(n << i) >> 7;*/ /*statement 3*/
printf("n = %c\n", n);

return 0;
}
/***************end of bitwise_shift***************/


As you have guessed correctly, the reason for the different values is
integral promotion.

In statement 0 the type of the operands are promoted to int (which can
at least store 15 bit unsigned number).
The result of shifting 0x79 by 2 is 0x1E4, but when you store the value
into m, only the modulo 256 of the value is stored back (ie. 0xE4) due
to implicit typecast to unsigned char. The value 0xE4 is then shifted
right by 7 which gives 1 as result.

Whereas in statement 1, the value 0x1E4 is shifted right by 7 without
truncation which gives 3 as a result.

And there is no difference between statement 1 and 2.

In statement 3, the value 0x1E4 is typecasted to unsigned char which
results in 0xE4 and then shifted right by 7 which is same as the
statement 0.

Hi, suresh
Thank you very much. Your explain makes me more clear.

Feb 23 '06 #3
kernelxu wrote:
...when I run the following program with some little changes,
the result confused me.
...
Any comments are appreciated in advance.
/**************bitwise_shift.c**************/
#include <stdio.h>

int main(void)
{
unsigned char c = 0x79;
unsigned char m;
unsigned char n;
unsigned char i = 2;

printf("sizeof(unsigned char) = %u\n", sizeof(unsigned char));
The sizeof operator produces a value of type size_t. Whilst size_t must
be an unsigned integer type, there is no requirement in C that it be
unsigned int. Under C99, you can use %zu to print a size_t value.
Under C90, you're better off casting the sizeof result to unsigned int
or unsigned long (and using %lu.)

That said, you do realise that sizeof(unsigned char) is _always_ 1
on any conforming implementation? You're better off printing
CHAR_BIT from <limits.h>.
m = c;
m <<= i;
m >>= 7U;
Your U suffix is completely redundant.
printf("m = %c\n", m);
You have no guarantee that the value you're printing is actually
a printable character. Use %x or %X instead, or write a small
routine to dump the binary contents...

#include <limits.h>

void dump_uc(unsigned char x)
{
unsigned char m;
for (m = -1, m = m/2+1; m; m >>= 1)
putchar('0' + !!(x & m));
}

void dump_u(unsigned x)
{
unsigned m;
for (m = -1, m = m/2+1; m; m >>= 1)
putchar('0' + !!(x & m));
}
n = c;
n = (n << i) >> 7U; /*statement 1*/
The result of (n << i) will be promoted before shifting occurs.
Again, the U suffix is redundant.
/*n = (n << 2U) >> 7U;*/ /*statement 2*/
/* n = (unsigned char)(n << i) >> 7;*/ /*statement 3*/


Each assignment will result in a conversion of the expression value
to the (unqualified) type of the object being assigned. The expression
0x79 << 2 is always going to produce 0x1E4. When that is assigned
to an 8-bit unsigned char (as your implementation presumably is),
it's going to be converted to 0xE4.

Without the conversion, (0x79 << 2) >> 7 is going to produce 0x03.

The effect of the prior assignment means the result is the same
as...

((unsigned char) 0x79 << 2) >> 7

<snip>

--
Peter

Feb 23 '06 #4

Peter Nilsson wrote:
kernelxu wrote:
...when I run the following program with some little changes,
the result confused me.
...
Any comments are appreciated in advance.
/**************bitwise_shift.c**************/
#include <stdio.h>

int main(void)
{
unsigned char c = 0x79;
unsigned char m;
unsigned char n;
unsigned char i = 2;

printf("sizeof(unsigned char) = %u\n", sizeof(unsigned char));


The sizeof operator produces a value of type size_t. Whilst size_t must
be an unsigned integer type, there is no requirement in C that it be
unsigned int. Under C99, you can use %zu to print a size_t value.
Under C90, you're better off casting the sizeof result to unsigned int
or unsigned long (and using %lu.)

That said, you do realise that sizeof(unsigned char) is _always_ 1
on any conforming implementation? You're better off printing
CHAR_BIT from <limits.h>.
m = c;
m <<= i;
m >>= 7U;


Your U suffix is completely redundant.
printf("m = %c\n", m);


You have no guarantee that the value you're printing is actually
a printable character. Use %x or %X instead, or write a small
routine to dump the binary contents...

#include <limits.h>

void dump_uc(unsigned char x)
{
unsigned char m;
for (m = -1, m = m/2+1; m; m >>= 1)
putchar('0' + !!(x & m));
}

void dump_u(unsigned x)
{
unsigned m;
for (m = -1, m = m/2+1; m; m >>= 1)
putchar('0' + !!(x & m));
}
n = c;
n = (n << i) >> 7U; /*statement 1*/


The result of (n << i) will be promoted before shifting occurs.
Again, the U suffix is redundant.
/*n = (n << 2U) >> 7U;*/ /*statement 2*/
/* n = (unsigned char)(n << i) >> 7;*/ /*statement 3*/


Each assignment will result in a conversion of the expression value
to the (unqualified) type of the object being assigned. The expression
0x79 << 2 is always going to produce 0x1E4. When that is assigned
to an 8-bit unsigned char (as your implementation presumably is),
it's going to be converted to 0xE4.

That's the key point. statement 3 (/* n = (unsigned char)(n << i) >>
7;*/ )
does the same job as statements" m <<= i; m >>= 7U;" do, which is to
truncate 0x1E4 to 0xE4.

Peter, thanks.

....snip...

Feb 23 '06 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

11
by: Randell D. | last post by:
Why would one use bitwise operators? I can program in various languages in some shape or form (C++, PHP, some scripting) and I've heard/seen bitwise operators before, but never understood why...
8
by: Rade | last post by:
Following a discussion on another thread here... I have tried to understand what is actually standardized in C++ regarding the representing of integers (signed and unsigned) and their conversions....
3
by: sandy_pt_in | last post by:
Hi C guru's can you please tell me how to do multiplication of 2 numbers using bitwize operators?? expecting reply.
8
by: Paul E Collins | last post by:
Suppose I have a few Keys objects: Keys k1 = Keys.V; // V Keys k2 = Keys.Control | Keys.V; // Ctrl+V Keys k3 = Keys.Shift | Keys.J; // Shift+J I need to determine which of these include the...
10
by: chanma | last post by:
code1:var x=0xf0000000; alert(x); output:4026531840 code2:var b=0xf<<28; alert(b); output:-268435456
5
by: noridotjabi | last post by:
I'm learning to program in C and any tutorial or book that I read likes to briefly touch on birdies operators and then move on without giving any sort of example application of them. Call me what...
5
by: Gigs_ | last post by:
Can someone explain me bitwise expression? few examples for every expression will be nice x << y Left shift x >y Right shift x & y Bitwise AND x | y Bitwise OR x ^ y Bitwise XOR (exclusive...
4
by: Felix Kater | last post by:
Hi, when I use something like int Shift= 3; long Value= 1 << Shift; What is the data type of the const value '1' here? In other terms: What is the possible maximum of 'Shift' here?
12
by: British0zzy | last post by:
Is it a defined operation when I do something like this: char a = 15; a = a<<9;
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.