将值分配给数组需要memcpy

Eri*_*ric 3 c arrays linker

我遇到了一个奇怪的错误.

我正在为引导加载程序编写代码,所以我没有很多花哨的库.

代码本身很简单,就是这样

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可执行文件,不确定它来自哪里.

另一个奇怪的事情是,当我把它放在一个函数中时,这是有问题的,但如果我全局声明数组,那么没有问题.

eca*_*mur 8

您的编译器正在执行时空权衡.

对于较小的数组,编译器会发出单独的指令来初始化堆栈上的每个数组插槽:

mov [ebp-4], 1
mov [ebp-8], 2
mov [ebp-12], 3
...
Run Code Online (Sandbox Code Playgroud)

对于较大的数组,编译器将数据放在程序的只读数据段中,并使用memcpy以下方法将其复制到堆栈中:

.rodata:
    _array_initialiser = { 1, 2, 3, ... }

push ebp-4
push _array_initialiser
push 32
call memcpy
Run Code Online (Sandbox Code Playgroud)

这就是为什么制作数组文件范围或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];
Run Code Online (Sandbox Code Playgroud)

另一种选择是以编程方式生成数组; 它看起来像一个简单的for循环将起作用.

第三种选择是自己编写和链接memcpy; 它不应该需要多行代码.