以下是6.7.6.3/7含义的解释:
如果关键字
static
也出现在数组的[
和]
中 类型派生,然后对于函数的每次调用, 相应的实际参数应提供对第一个参数的访问 数组的元素,其元素的数量至少与 大小表达式。
目前尚不清楚其含义。我运行了以下示例:
main.c
#include "func.h"
int main(void){
char test[4] = "123";
printf("%c\n", test_func(2, test));
}
和test_func
的2种不同实现:
func.h
char test_func(size_t idx, const char[const static 4]);
func.c
char test_func(size_t idx, const char arr[const static 4]){
return arr[idx];
}
func.h
char test_func(size_t idx, const char[const 4]);
func.c
char test_func(size_t idx, const char arr[const 4]){
return arr[idx];
}
在两种情况下,我都检查了使用该函数的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
您能举个例子,与非静态关键字相比,静态关键字能带来一些好处(或根本没有区别)吗?
答案 0 :(得分:11)
以下是static
实际上有所作为的示例:
unsigned foo(unsigned a[2])
{
return a[0] ? a[0] * a[1] : 0;
}
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
但是在将功能参数替换为unsigned a[static 2]
之后,结果很简单
foo:
mov eax, dword ptr [rdi + 4]
imul eax, dword ptr [rdi]
ret
由于a[0] * a[1]
会计算a [0]是否为零的正确结果,因此不需要条件分支。但是,如果没有static
关键字,则编译器无法假定a [1]可以访问,因此必须检查a [0]。
目前只有clang进行此优化;在两种情况下,ICC和gcc都会生成相同的代码。
答案 1 :(得分:6)
根据我的经验,编译器并没有太多使用它,但是一种用法是,编译器可以假定(数组衰减为指针)参数不是NULL
。
使用此功能,gcc和clang(x86)在-O3
处产生相同的机器代码:
int func (int a[2])
{
if(a)
return 1;
return 0;
}
反汇编:
func:
xor eax, eax
test rdi, rdi
setne al
ret
将参数更改为int a[static 2]
时,gcc会提供与以前相同的输出,但是clang做得更好:
func:
mov eax, 1
ret
因为clang意识到a
永远不能为NULL,所以它可以跳过检查。