de1337ed
de1337ed

Reputation: 3325

Long type 64bit linux

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

Answers (5)

Gunther Piez
Gunther Piez

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

Morpfh
Morpfh

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

Pavan Manjunath
Pavan Manjunath

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

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

Michael
Michael

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

Related Questions