以下原型(prototype)之间有什么实际区别吗?
void f(const int *p);
void f(const int *restrict p);
void f(const int *volatile p);
C11 6.7.6.3/15 部分(最后一句)表示,为了确定类型兼容性,不考虑顶级限定符,即允许函数定义在其参数上具有不同的顶级限定符比原型(prototype)声明有。
但是(与 C++ 不同)它并没有说它们会被完全忽略。在 const
的情况下,这显然没有实际意义;但是在 volatile
和 restrict
的情况下可能会有不同。
示例:
void f(const int *restrict p);
int main()
{
int a = 42;
const int *p = &a;
f(p);
return a;
}
原型(prototype)中存在 restrict
是否允许编译器针对 return a;
优化 a
的读取?
( Related question )
最佳答案
如果标准中没有任何内容,则由编译器决定,但似乎至少对于 gcc 4.9(对于 x86)它们被忽略了。检查我用来取笑编译器的这个小片段:
static int b;
void f(const int *p) {
b = *p + 1;
}
int main()
{
int a = 42;
const int *p = &a;
f(p);
return a;
}
如果我按原样编译它,我会得到
f(int const*):
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movl (%rax), %eax
addl $1, %eax
movl %eax, b(%rip)
popq %rbp
ret
main:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl $42, -12(%rbp)
leaq -12(%rbp), %rax
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rdi
call f(int const*)
movl -12(%rbp), %eax
leave
ret
如果我使用void f(const int *__restrict__ p)编译它
f(int const*):
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movl (%rax), %eax
addl $1, %eax
movl %eax, b(%rip)
popq %rbp
ret
main:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl $42, -12(%rbp)
leaq -12(%rbp), %rax
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rdi
call f(int const*)
movl -12(%rbp), %eax
leave
ret
Anf 最后,如果我使用 void f(const int *__volatile__ p) 编译它,我会得到
f(int const*):
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movl (%rax), %eax
addl $1, %eax
movl %eax, b(%rip)
popq %rbp
ret
main:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl $42, -12(%rbp)
leaq -12(%rbp), %rax
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rdi
call f(int const*)
movl -12(%rbp), %eax
leave
ret
所以在实践中它们似乎在 C 中也被忽略了。
关于c - 函数原型(prototype)中的顶级 volatile 或 restrict 是否重要?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28819855/