由于我对cpu寄存器不太熟悉,一般而言,在任何体系结构中都特别使用x86,如果使用VC ++编译器相关,我很好奇,对于具有少量元素的数组的所有元素都是可能的就像一个1字节字符的数组,有4个元素驻留在某个cpu寄存器中,因为我知道对于像double,integer等单个基元来说这可能是真的吗?
当我们有如下参数时:
void someFunc(char charArray[4]){
//whatever
}
这个参数传递肯定是通过传递指向函数的指针来完成的,或者该数组是否会驻留在某个cpu寄存器中,而不需要将指针传递给主存储器?
答案 0 :(得分:5)
这依赖于不编译器,也不可能。数组不能以与其他类型相同的方式传递值,即传递给函数时不能复制它们。 C ++标准很明确,因为在声明中处理函数签名时,以下是完全等价的:
void foo( char *a );
void foo( char a[] );
void foo( char a[4] );
void foo( char a[ 100000 ] );
兼容的编译器会将函数签名中的数组转换为指针。现在,在调用的地方,会发生类似的操作:如果参数是一个数组,编译器必须将它衰减成指向第一个元素的指针。同样,数组的大小在衰减中丢失。
特定寄存器可用于保存多个值并对其执行操作(google用于矢量化操作,MME和变体)。但是,这意味着编译器实际上可以将小数组的内容插入到单个寄存器中,这不能用于更改您引用的函数调用。
答案 1 :(得分:4)
在单个函数中,只要编译器能够根据代码指示生成CPU指令来操作它,就可以将数组保存在一个或多个寄存器中。该标准并未真正定义在寄存器中“成为”的含义。这是编译器和调试器之间的私事,并且寄存器中的某些东西之间可能存在细微差别,并且完全“优化掉”。
在您的示例中,参数是指针,而不是数组(请参阅dribeas的回答)。因此,它指向的数组可能会被保存为寄存器,这是不寻常的。您可能处理的“主要”体系结构不允许指向寄存器的指针,因此即使数组保存在调用代码的寄存器中,也必须将其写入内存以获取指针它,传递给被叫者。
如果内联函数调用,则可能会进行更好的优化,就好像根本没有调用一样。
如果将数组包装在结构中,则将其转换为可以通过值传递的内容:
struct Foo {
char a[4];
};
void FooFunc(Foo f) {
// whatever
}
现在,该函数将实际的数组数据作为参数,因此将它保存在寄存器中的障碍就更少了。但是,实现的调用约定是否实际上传递了寄存器中的小结构是另一个问题。我不知道调用约定是做什么的,如果有的话。
答案 2 :(得分:1)
我非常熟悉的5个左右的编译器,(来自1.0的Borland / Turbo C / C ++,来自v8.0的Watcom C / C ++,来自5.0的MSC,IBM Visual Age C / C ++,各种gcc) DOS,Linux和Windows上的版本)我没有看到这种优化自然发生。
有一个字符串库,其名称我记不清了,它在x86 ASM中做了类似的优化。它可能是“自发大会”图书馆的一部分,但没有保证。
答案 3 :(得分:1)
接受数组的函数可能会索引到该数组中。我知道没有支持高效索引到寄存器的架构,所以在寄存器中传递数组可能毫无意义。
(在x86架构上,您可以通过访问a[0]
注册表的a[1]
和al
来访问ah
和eax
,但这是一个特殊的仅在编译时已知索引时才有效的情况。)
答案 4 :(得分:0)
你问x86上VC ++是否可行。
我怀疑这种配置是否可行。是的,您可以生成汇编代码,其中该数组保存在寄存器中,但由于数组的性质,它绝不是编译器的自然优化,所以我怀疑它们是否将它放入。
你可以尝试一下,然后产生一些代码,其中编译器会有“激励”将它放入寄存器,但它看起来很奇怪,如
char x[4];
*((int*)x) = 36587467;
使用优化和/ FA开关编译并查看生成的汇编代码(然后告诉我们结果: - ))
如果以更“自然”的方式使用它,比如访问单个字符或用字符串初始化它,编译器根本没有理由将该数组放入寄存器。
即使将其传递给函数 - 编译器也可能将数组的地址放入寄存器,而不是数组本身
答案 5 :(得分:-1)
只有变量可以存储在寄存器中。您可以尝试使用register
关键字强制注册存储:register int i;
数组是默认指针。
您可以像这样获取位于4位置的值(使用指针语法):
char c = *(charArray + 4);