St.*_*rio 6 c assembly gcc x86-64 language-lawyer
以下是6.7.6.3/7含义的解释:
如果关键字
static也出现在[和]的数组类型推导中,则对于函数的每次调用,相应实际参数的值应提供对数组第一个元素的访问,该元素的大小至少与size指定的数量相同表达。
含义还不清楚。我运行了以下示例:
main.c
#include "func.h"
int main(void){
char test[4] = "123";
printf("%c\n", test_func(2, test));
}
Run Code Online (Sandbox Code Playgroud)
以及2种不同的实现test_func:
func.h
char test_func(size_t idx, const char[const static 4]);
Run Code Online (Sandbox Code Playgroud)
func.c
char test_func(size_t idx, const char arr[const static 4]){
return arr[idx];
}
Run Code Online (Sandbox Code Playgroud)
func.h
char test_func(size_t idx, const char[const 4]);
Run Code Online (Sandbox Code Playgroud)
func.c
char test_func(size_t idx, const char arr[const 4]){
return arr[idx];
}
Run Code Online (Sandbox Code Playgroud)
gcc 7.4.0 -O3在这两种情况下,我都检查了用该函数编译的汇编代码,结果完全相同:
拆卸功能
(gdb) disas main
sub rsp,0x18
mov edi,0x2
lea rsi,[rsp+0x4]
mov DWORD PTR [rsp+0x4],0x333231
mov rax,QWORD PTR fs:0x28
mov QWORD PTR [rsp+0x8],rax
xor eax,eax
call 0x740 <test_func>
[...]
(gdb) disas test_func
movzx eax,BYTE PTR [rsi+rdi*1]
ret
Run Code Online (Sandbox Code Playgroud)
您能否举一个例子,与非静态对应项相比,static关键字具有一些好处(或根本没有区别)?
dpi*_*dpi 11
这是一个static实际上有所作为的示例:
unsigned foo(unsigned a[2])
{
return a[0] ? a[0] * a[1] : 0;
}
Run Code Online (Sandbox Code Playgroud)
clang(对于x86-64,带有-O3)将其编译为
foo:
mov eax, dword ptr [rdi]
test eax, eax
je .LBB0_1
imul eax, dword ptr [rdi + 4]
ret
.LBB0_1:
xor eax, eax
ret
Run Code Online (Sandbox Code Playgroud)
但是用替换功能参数后unsigned a[static 2],结果很简单
foo:
mov eax, dword ptr [rdi + 4]
imul eax, dword ptr [rdi]
ret
Run Code Online (Sandbox Code Playgroud)
条件分支不是必需的,因为a[0] * a[1]评估a [0]是否为零可得出正确的结果。但是,如果没有static关键字,编译器将无法假定可以访问a [1],因此必须检查a [0]。
当前只有clang进行此优化。在两种情况下,ICC和gcc都会生成相同的代码。
根据我的经验,编译器并没有太多使用它,但是一种用法是,编译器可以假设参数(数组衰减为指针)不是NULL。
有了这个功能,gcc和clang(x86)会在-O3以下位置产生相同的机器代码:
int func (int a[2])
{
if(a)
return 1;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
拆卸:
func:
xor eax, eax
test rdi, rdi
setne al
ret
Run Code Online (Sandbox Code Playgroud)
将参数更改int a[static 2]为时,gcc会提供与以前相同的输出,但是clang可以做得更好:
func:
mov eax, 1
ret
Run Code Online (Sandbox Code Playgroud)
由于clang意识到a永远不能为NULL,因此可以跳过检查。