6

这是我的代码:

#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 的值..

有人对此有想法吗?

4

5 回答 5

7

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

#define N 3000000000UL

但是,(根据您对 HLundvall 的回答的评论)relocation truncated to fit错误显然不是由于这个原因——它可能(正如 Mystical 和 Matt Lacey 所说)太大而无法适应该细分市场。


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

例如:

  • 您的示例代码仅使用所示代码中每个字节的低半字节:您可以将其打包成一半大小(诚然,这仍然太大了)
  • 根据您的访问模式,您可能能够将阵列保留在磁盘上并将工作子集缓存在内存中
  • 如果我们知道您需要什么,可能会有更好的整体算法和数据结构
于 2012-08-15T23:43:09.970 回答
5

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

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

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

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

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


  1. 一般而言,标准所称的具有静态存储持续时间的变量。
于 2012-08-15T23:48:46.417 回答
1

问题在于 gcc(默认情况下)使用 pc 相对访问来获取 x86_64 目标上的静态数据对象的地址,并且这些访问最多限制为 2^31 字节。因此,如果符号最终被放置在距离访问它的代码超过 2GB 的地方,当它尝试使用太大而无法容纳在操作说明。

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

请注意,常量字面量的类型后缀大多是无关紧要的——对于 int 来说太大的常量字面量将自动变成没有任何后缀的 long(如果需要,甚至可以变成 long long)。请参阅 C99 规范的 6.4.4.1.5。

于 2012-08-16T00:18:13.793 回答
1

要输入 unsigned long 类型的数字常量,请使用:

#define N 3000000000UL
于 2012-08-15T23:43:39.890 回答
-1

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

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

于 2012-08-16T00:24:43.677 回答