Reputation: 3325
Very simple questions guys, but maybe I'm just forgetting something. In 64bit linux, a long is 8bytes correct? If that's the case, and I want to set the 64th bit, I can do the following:
unsigned long num = 1<<63;
Whenever I compile this, however, it gives me an error saying that I'm left shifting by more than the width. Also, if I wanted to take the first 32bits of a long type (without sign extension), can I do:
num = num&0xFFFFFFFF;
or what about:
num = (int)(num);
Thank you.
Upvotes: 6
Views: 39472
Reputation: 30449
AFAIR code like this was the source of a major bug in reiserfs a few years ago:
unsigned long num = 1<<63;
If you speak of x86_64, yes, a long is 64 bit and on most other 64 bit linux platforms too. The problem is that both the 1
and the 63
in your code are simple int
, and so the result is undefined. Better use
unsigned long num = 1UL<<63;
or
unsigned long num = (unsigned long)1<<63;
Upvotes: 1
Reputation: 4093
For portability you could use:
limits.h
#define LNG_BIT (sizeof(long) * CHAR_BIT)
unsigned long num = 1UL << (LNG_BIT - 1);
To get "low int", something like?:
#define INT_BIT (sizeof(int) * CHAR_BIT)
if (LNG_BIT > INT_BIT)
return num & (~0UL >> INT_BIT);
else
return num;
or
num &= ~(~0U << INT_BIT);
Or, use mask, etc. Depends in large on why, for what, etc. you want the int bits.
Also notice the options given by compilers; I.e. if you are using gcc:
-m32
-m64
-mx32
Generate code for a 32-bit or 64-bit environment.
* The -m32 option sets int, long, and pointer types to 32 bits, and generates code that runs on any i386 system.
* The -m64 option sets int to 32 bits and long and pointer types to 64 bits, and generates code for the x86-64 architecture. For Darwin only the -m64 option also turns off the -fno-pic and -mdynamic-no-pic options.
* The -mx32 option sets int, long, and pointer types to 32 bits, and generates code for the x86-64 architecture.
There is also -maddress-mode=long
etc.
-maddress-mode=long
Generate code for long address mode. This is only supported for 64-bit and x32 environments. It is the default address mode for 64-bit environments.
Upvotes: 1
Reputation: 28555
In 64bit linux, a long is 8bytes correct?
Need not be. Depends on the compiler than on the underlying OS. Check this for a nice discussion. What decides the sizeof an integer?
Whenever I compile this, however, it gives me an error saying that I'm left shifting by more than the width
Everyone have already answered this. Use 1UL
Also, if I wanted to take the first 32bits of a long type (without sign extension), can I do:
num = num&0xFFFFFFFF;
or what about:
num = (int)(num);
num = num&0xFFFFFFFF
. This will give you the lower 32-bits. But note that if long
is just 4 bytes on your system then you are getting the entire number. Coming to the sign extension part, if you've used a long
and not unsigned long
then you cannot do away with the sign extended bits. For example, -1
is represented as all ones, right from the 0th bit. How will you avoid these ones by masking?
num = (int)(num)
will give you the lower 32-bits but compiler might through a Overflow Exception warning if num
does not fit into an int
Upvotes: 4
Reputation: 1
Actually, if you want some precise length (in bits) for your integers, assuming a C99 conforming compiler, #include <stdint.h>
and use types like int64_t
, int32_t
etc. A handy type is intptr_t
, an integer type with the same number of bits as void*
pointer (so you can call it a machine "word")
Upvotes: 4
Reputation: 2261
I believe the problem with the first question is that the compiler is treating '1' as an integer, not as a long integer. It doesn't figure it out until after the assignment.
You can fix it by doing:
unsigned long num = (unsigned long)1<<63;
Upvotes: 0