LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Software > Linux - Kernel
User Name
Password
Linux - Kernel This forum is for all discussion relating to the Linux kernel.

Notices


Reply
  Search this Thread
Old 07-07-2009, 12:55 PM   #1
ranthal
LQ Newbie
 
Registered: Jun 2009
Location: Carlsbad, CA
Posts: 24

Rep: Reputation: 15
Bit shifting 6-byte value into a u64


Hey all,

I'm getting a compiler warning stating that the left shift count is >= the width of the type about code that is bit shifting a 6-byte (8 bit/byte) value into a u64. Is there a better way to perform this operation? Currently the code is:
Code:
u64_val = ((u8_val[0] << 40) | \
           (u8_val[1] << 32) | \
           (u8_val[2] << 24) | \
           (u8_val[3] << 16) | \
           (u8_val[4] << 8) | \
           (u8_val[5]));
Essentially I want the extra 16 bytes to be zero padded out since both values represent an unsigned integer that is represented by 48 bits.
 
Old 07-07-2009, 01:04 PM   #2
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
I'm not sure whether there is a better way than correcting the code you have. But I understand the bug in your code that you seem to not understand.

Take a simpler example

u64_val = u8_val << 40;

The language standard does not care about the destination for the '=' when it is interpreting the '<<'. The data types involved in that '<<' are based just on its operands. So you are doing a 40 bit left shift whose result has less than 40 bits, which is not what you intend.

To make the result of the left shift have 64 bits, you need to cast the input to have 64 bits before the shift. Maybe:

u64_val = (unsigned long long)u8_val << 40;

I understand you probably don't want all the excess processing that might imply (cast each 8 bit value to a 64 bit value and shift all those and or them all together). But in such cases there might not be any good alternative to simply coding it that way and trusting the optimizer to throw away most of the excess work.
 
Old 07-07-2009, 01:30 PM   #3
ranthal
LQ Newbie
 
Registered: Jun 2009
Location: Carlsbad, CA
Posts: 24

Original Poster
Rep: Reputation: 15
Quote:
Originally Posted by johnsfine View Post
But I understand the bug in your code that you seem to not understand.

Take a simpler example

u64_val = u8_val << 40;

The language standard does not care about the destination for the '=' when it is interpreting the '<<'. The data types involved in that '<<' are based just on its operands. So you are doing a 40 bit left shift whose result has less than 40 bits, which is not what you intend.
Ah, I think you got it right. I was worried there was some sort of architecture dependency on the u64 type. Looks like instead the bit shift was on a 32-bit boundary. So I casted it like you mentioned and it got rid of the warning. I am a little concerned about the overhead involved here so maybe there are some other suggestions?

Maybe it would be better to create a 64-bit buffer of u8, memset it to 0, memcpy the 48-bit value to &buf[2], then memcpy buf into u64_val?
 
Old 07-07-2009, 01:48 PM   #4
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
Quote:
Originally Posted by ranthal View Post
Maybe it would be better to create a 64-bit buffer of u8, memset it to 0, memcpy the 48-bit value to &buf[2], then memcpy buf into u64_val?
What architecture are you doing this on? Or do you intend the code to be portable across architectures?

In i386 and x86_64 architectures, values are stored least significant byte first. So the least significant byte (coming from u8_val[5] in your code) goes to buf[0] and the next least significant (from u8_val[4]) goes to buf[1] and up to the most significant from u8_val[0] to buf[5].

Your idea, which I quoted above, assume the opposite. That would be correct in some less common architectures.

The fact that you can get details like that easily wrong, is even more reason to trust the optimizer and code just what you want done, not some alternative you think might be faster.

I'm usually on the other side of that argument. I push a little harder than other programmers for best speed in almost everything I code. I totally reject the often quoted nonsense about "premature optimization". But the compiler may do surprisingly well optimizing out the excess work if you code this the robust way, and even I can't think of an alternative that would clearly result in faster code. Your idea, properly corrected, probably would just make it slower.

If I really really needed fast code in this situation, I'd write the robust version, then look at the generated asm code, then decide what to do about it. But I assume you don't know enough asm coding for that to help.

Probably the robust code with all the casts and shifts is your best bet.
 
Old 07-07-2009, 02:05 PM   #5
ranthal
LQ Newbie
 
Registered: Jun 2009
Location: Carlsbad, CA
Posts: 24

Original Poster
Rep: Reputation: 15
Quote:
Originally Posted by johnsfine View Post
What architecture are you doing this on? Or do you intend the code to be portable across architectures?
Portability is definitely an issue. I've been developing on a PowerPC (MPC 8313) and it will be used on an ARM (OMAP 2430). The reason for this is outside of the scope of this discussion but you make an excellent point on which order the bytes are stored in so I guess the cast will have to do.
 
Old 07-07-2009, 09:26 PM   #6
JimHughen
Member
 
Registered: Jun 2009
Location: Austin, Texas
Distribution: Ubuntu
Posts: 44

Rep: Reputation: 16
Another method to modify a u64 with u8's is to make a union with a u64 and u8[8]. You can then write the u8[] part of the union and read the u64.

Compilers are pretty good at this sort of thing. Probably either method will generate similar or equivalent instructions.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Need to copy an entire disk byte-for-byte Pawprint Linux - Software 6 06-16-2011 11:01 AM
shifting from RHEL3 to RHEL5 oracle_on_linux Linux - Hardware 1 01-03-2008 05:35 PM
byte to byte remote comparison louisJ Linux - Newbie 3 09-21-2007 05:28 PM
shifting samba ilnli Linux - Software 0 03-07-2006 02:38 AM
backup byte-for-byte axion0917 Linux - Software 2 12-11-2003 05:01 PM

LinuxQuestions.org > Forums > Linux Forums > Linux - Software > Linux - Kernel

All times are GMT -5. The time now is 10:09 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration