我遇到了一个奇怪的错误。
我正在为引导程序编写代码,所以我没有很多花哨的库。
代码本身非常简单,它是
int array[32] = { 1, 2, 3, [...snip...], 31, 32 };
此代码导致未解决的memcpy未解决的外部问题。 但是,此代码编译并链接正常
int array[12] = { 1, 2, 3, [...snip...], 11, 12 };
实际上,错误发生在
之间 int array[12] = { 0 };
和
int array[13] = { 0 };
第一个链接很好,但第二个链接无法链接。我只是不明白为什么在13号,编译器突然决定依赖memcpy来做事情。我尝试了-O0和-O3。我的编译器是一个名为cl470的Windows可执行文件,不确定它来自何处。
另一个奇怪的事情是,当我把它放在一个函数中时,这是有问题的,但如果我全局声明数组,那么就没有问题了。
答案 0 :(得分:8)
您的编译器正在执行time-space tradeoff。
对于较小的数组,编译器会发出单独的指令来初始化堆栈中的每个数组插槽:
mov [ebp-4], 1
mov [ebp-8], 2
mov [ebp-12], 3
...
对于较大的数组,编译器将数据放在程序的read-only data segment中并使用memcpy
将其复制到堆栈中:
.rodata:
_array_initialiser = { 1, 2, 3, ... }
push ebp-4
push _array_initialiser
push 32
call memcpy
这就是为什么使数组文件范围或static
将消除memcpy
;数组可以直接放在数据段中,并在编译时初始化。
将memcpy
用于更大的数组会更有效,因为它可以减少代码大小,从而减少instruction cache次丢失。
您可以尝试的一些事情是将数组移动到文件范围或自己使其静态;如果你需要它每次通过数组重新初始化你可以手动将它复制到本地数组(虽然编译器也可以将这样的循环转换为memcpy
!)
static const int array_data[] = { 1, 2, 3, ... };
int array[sizeof(array_data) / sizeof(array_data[0]))];
for (size_t i = 0; i < sizeof(array_data) / sizeof(array_data[0])); ++i)
array[i] = array_data[i];
另一种选择是以编程方式生成数组;它看起来像一个简单的for
循环。
第三种选择是在您自己的memcpy
中编写和链接;它不应该需要多行代码。
答案 1 :(得分:1)
以下代码将存储在可执行文件中的数据复制到堆栈中。
int array[12] = { blah };
我猜优化器在数组大小大于某个数字时使用memcpy。
你可能想这样做:
static int array[12] = { blah };
通过使用static关键字,可以防止编译器生成将静态数据复制到堆栈的代码。