长整型64位Linux系统

6

这是一些非常简单的问题,但我可能只是忘了一些东西。 在64位的Linux系统中,long类型是8个字节,对吗? 如果是这样的话,如果我想设置第64位,我可以执行以下操作:

unsigned long num = 1<<63;

每次编译时,却出现错误提示我正在进行超范围左移位操作。另外,如果我想要获取long类型的前32位(不进行符号扩展),我可以这样做:
num = num&0xFFFFFFFF;

或者考虑:

num = (int)(num);

谢谢。


5
尝试:unsigned long num = 1UL << 63; - Mysticial
@Mysticial,为什么不把整数提升的东西和答案一起发布呢? - cnicutar
1
取决于使用的编译器。许多旧版编译器默认为32位长整型,即使在64位机器上运行也是如此。在进一步操作之前,请确认 sizeof num 的大小为8。 - wallyk
2
@cnicutar 当你一遍又一遍地回答相同的问题时,它开始变得乏味。所以我无法做出超过一行的回答... - Mysticial
可能是重复的问题:警告:左移位计数>=类型宽度 - Bo Persson
5个回答

4
在64位的Linux中,一个long型变量占8个字节,对吗?其实不一定,这取决于编译器而不是底层操作系统。可以参考这里的讨论:What decides the sizeof an integer? 你提到编译时会报错提示"left shifting by more than the width"问题,已经有其他人回答了,建议使用1UL
此外,如果想要从一个long类型的变量中获取前32位(不带符号扩展),应该怎么做呢?
num = num&0xFFFFFFFF;
or what about:

num = (int)(num);

num = num&0xFFFFFFFF。这将给您低32位。但请注意,如果您的系统上的long只有4个字节,则会得到整个数字。关于符号扩展部分,如果您使用了long而不是unsigned long,则无法摆脱符号扩展位。例如,-1被表示为所有位都是1,从第0位开始。如何通过掩码避免这些1?

num = (int)(num)将给您低32位,但如果num不适合int,编译器可能会发出溢出异常警告。


4
同意在64位机器上C语言不强制long类型为64位。但是Linux隐式地要求long类型为64位。只需看看通过unsigned long传递的所有指针和通过signed long传递的内存偏移量(例如系统调用)即可。因此,只要Linux源代码没有发生根本性的改变,我会回答“在64位Linux中,long类型为8字节,对吗?”的问题为 - Yves Lhuillier

4

实际上,如果您想要为整数指定精确的位数(以位为单位),假设您使用符合C99标准的编译器,请使用#include <stdint.h>并使用诸如int64_tint32_t等类型。一个方便的类型是intptr_t,它是一种与void*指针具有相同位数的整数类型(因此您可以将其称为机器“字”)。


2
符合C99标准的编译器不需要提供固定宽度类型,例如int64_t。只有提供8位、16位、32位和64位整数类型且没有填充位的二进制补码实现才必须stdint.h中提供固定宽度整数typedefs。 - dreamlax

1

为了可移植性,您可以使用:

limits.h

#define LNG_BIT   (sizeof(long) * CHAR_BIT)

unsigned long num = 1UL << (LNG_BIT - 1);

如何获取“低整数”?类似这样的代码:
#define INT_BIT   (sizeof(int) * CHAR_BIT)

if (LNG_BIT > INT_BIT)
    return num & (~0UL >> INT_BIT);
else
    return num;

或者

    num &= ~(~0U << INT_BIT);

或者,使用掩码等。这在很大程度上取决于您想要整数位的原因和用途。

还要注意编译器提供的选项;例如,如果您正在使用gcc:

-m32
-m64
-mx32
生成适用于32位或64位环境的代码。
* -m32选项将int、long和指针类型设置为32位,并生成可在任何i386系统上运行的代码。
* -m64选项将int设置为32位,将long和指针类型设置为64位,并为x86-64架构生成代码。对于Darwin,仅-m64选项还会关闭-fno-pic和-mdynamic-no-pic选项。
* -mx32选项将int、long和指针类型设置为32位,并为x86-64架构生成代码。

还有-maddress-mode=long等选项。

-maddress-mode=long
生成长地址模式的代码。这仅适用于64位和x32环境。它是64位环境的默认地址模式。


1

我记得几年前,像这样的代码是reiserfs中一个重大错误的源头:

unsigned long num = 1<<63;

如果你说的是x86_64,那么long就是64位,在大多数其他64位Linux平台上也是如此。问题在于你代码中的1和63都是简单的int类型,因此结果是未定义的。最好使用

 unsigned long num = 1UL<<63;

或者

 unsigned long num = (unsigned long)1<<63;

0

我相信第一个问题出在编译器将'1'作为整数而非长整型处理。它直到赋值后才明白这一点。

您可以通过如下方式解决:

unsigned long num = (unsigned long)1<<63;

你是否知道我问题的第二部分的答案?关于获取非符号扩展的前32位?我需要做类似于num = num&(unsigned long)(0xFFFFFFFF)这样的操作吗? - de1337ed
@de1337ed,我已经回答了你问题的第二部分,请查看。 - Pavan Manjunath

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接