如何使用宏作为无符号长号?

时间:2012-08-15 23:39:51

标签: c++ c macros

这是我的代码:

#define MSK 0x0F
#define UNT 1
#define N 3000000000

unsigned char aln[1+N];
unsigned char pileup[1+N];

void set(unsigned long i)
{
    if ((aln[i] & MSK) != MSK ) {
        aln[i] += UNT;
    }
}
int main(void) {}

当我尝试编译它时,编译器抱怨如下:

 tmp/ccJ4IgSa.o: In function `set':
 bitmacs.c:(.text+0xf): relocation truncated to fit: R_X86_64_32S against symbol `aln' defined in COMMON \
 section in /tmp/ccJ4IgSa.o
  bitmacs.c:(.text+0x29): relocation truncated to fit: R_X86_64_32S against symbol `aln' defined in COMMON\
 section in /tmp/ccJ4IgSa.o
 bitmacs.c:(.text+0x32): relocation truncated to fit: R_X86_64_32S against symbol `aln' defined in COMMON\
  section in /tmp/ccJ4IgSa.o

我认为原因可能是N太大了,因为如果我将N改为2000000000它可以成功编译。但我需要3000000000作为N的值..

有人对此有所了解吗?

5 个答案:

答案 0 :(得分:6)

根据您的原始问题:使用整数文字后缀 UL (或类似)强制存储类型为N:

#define N 3000000000UL

然而,(根据你对HLundvall的回答的评论)relocation truncated to fit错误显然不是由于这个 - 它可能(正如Mystical和Matt Lacey所说)只是太大而不适合该段。


顺便说一句,如果你问一个单独的问题,解释你想要用你的巨大数组完成什么,有人可能会建议一个更好的解决方案(更有可能适合内存)

例如:

  • 您的示例代码仅使用显示的代码中每个字节的低半字节:您可以将其打包为一半大小(这无疑仍然太大)
  • 取决于您的访问模式,您可以将阵列保留在磁盘上并在内存中缓存一个有效的子集
  • 如果我们知道您需要什么,可能会有更好的整体算法和数据结构

答案 1 :(得分:5)

忽略数字文字不正确的“正式”问题(请参阅其他答案以获得正确的语法),这里的关键点是分配3 GB静态/全局是一个非常糟糕的主意阵列。

大多数平台上的

static和全局 1 变量直接从可执行映像映射,这意味着您的可执行文件必须大到3 GB,这甚至是相当大的对于当前的标准。即使在某些平台上可能会解除此限制(请参阅注释),您也无法控制如何处理分配失败。

最重要的是,全局变量并不适用于这么大的东西,并且您可能会发现链接器(例如您找到的)和加载器强加的任意限制问题。相反,您应该使用mallocnew或某些特定于平台的函数在堆上分配大于几KB的任何内容,在运行时优雅地处理可能的故障。

但是,请记住,对于在几乎任何32位操作系统下运行的应用程序,根据您的要求,不可能获得3 GB的连续内存,并且完全不可能获得多个这些数组(= 4 GB的连续内存)而不依赖于特定于平台的技巧(例如,在给定时刻仅映射内存中数组的特定部分)。

另外,您确定自从程序开始运行以来确实需要所有连续的内存吗?是不是有一些更好的数据结构/算法可以避免分配所有内存?


  1. 通常,标准使用静态存储持续时间调用变量。

答案 2 :(得分:1)

要输入unsigned long use类型的数字常量:

#define N 3000000000UL

答案 3 :(得分:1)

问题是gcc(默认情况下)使用pc相对访问来获取x86_64目标上的静态数据对象的地址,并且这些访问限制为最多2 ^ 31个字节。因此,如果符号最终放置距离访问它的代码超过2GB,当它尝试使用太大而不适合32位空间的偏移量时,最终会出现此链接错误。指令。

您可以使用gcc的-mcmodel=large选项来避免此问题。这告诉它不要假设它可以使用32位PC相对偏移来访问符号(除其他外)

请注意,常量文字的类型后缀几乎是无关紧要的 - 对于int来说太大的常量字面值将自动变为长(或者甚至很长,如果需要)而没有任何后缀。见C99规范的6.4.4.1.5。

答案 4 :(得分:-1)

您的可执行文件正在尝试将对象放在内存中超过4GB标记,这是不允许的。请看这个链接:http://www.technovelty.org/code/c/relocation-truncated.html

从文章中可以看出:“如果你看到这个并且你不是手工编码,你可能想要查看gcc的-mmodel参数。”