2012-08-31 108 views
3

我遇到了一个奇怪的错误。将值赋给数组需要memcpy

我正在为bootloader编写代码,所以我没有很多花哨的库和所有。

代码本身是很简单,这是

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

问题是,可能没有足够的堆栈来容纳一个13元素的int数组,所以编译器突然想要将它移动到堆上 - 也许使数组'static'可以解决问题。 – 2012-08-31 18:56:25

+1

哦,+1,因为这个问题真的没有意义。 (yupp I <3 Windows) – 2012-08-31 18:56:47

+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更大的阵列效率更高,因为它减少了代码大小,因此减少了错误。

你可以尝试的一些事情是将数组移动到文件范围或使其变为静态;如果你需要它遍历数组每次重新初始化,您可以手动将其复制到本地阵列(尽管编译器还可以转换这样一个循环为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

以下代码将存储在可执行文件中的数据复制到堆栈。

int array[12] = { blah }; 

我猜优化器在数组大小大于某个数时使用memcpy。

你可能想这样做:

static int array[12] = { blah }; 

通过使用static关键字可以防止编译器产生的代码拷贝静态数据到堆栈中。