[英]Is it possible to give a top-level function access to an object's members in C++?
[英]Is top-level volatile or restrict significant in a function prototype?
以下原型之间有什么实际区别?
void f(const int *p);
void f(const int *restrict p);
void f(const int *volatile p);
C11 6.7.6.3/15节(最后一句话)说,出于确定类型兼容性的目的,不考虑使用顶级限定符,即允许函数定义在其参数上具有与原型不同的顶级限定符宣言了。
但是(与C ++不同),它并没有说它们被完全忽略了。 对于const
这显然没有意义; 但是,在volatile
和restrict
的情况下,可能会有所不同。
例:
void f(const int *restrict p);
int main()
{
int a = 42;
const int *p = &a;
f(p);
return a;
}
原型中是否存在restrict
是否允许编译器优化对a
的读取以return a;
?
( 相关问题 )
如果标准中没有内容,则取决于编译器,但似乎至少对于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
最后,如果我使用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忽略。
假设f
的定义缺少restrict
限定符,则代码应定义良好。 C11(n1570)6.5.2.2(函数调用)p7 [emph。 我的,C99 TC3(n1256)中的措词相同]
如果表示被调用函数的表达式的类型确实包含原型,则将参数隐式转换为相应参数的类型,就像通过赋值一样,将每个参数的类型视为其声明的非限定版本。类型 。
使用不合格的参数(因此使用正确类型的参数)调用函数f
,并且其所有声明均为兼容类型(根据问题中的引号):该函数调用定义明确。 (如果标准中没有任何内容使其明确未定义。我认为没有。)
在函数的定义中存在应用于参数的顶级volatile
限定符可能会导致在某些情况下无法定义行为。 最为显着地:
int test(int volatile x)
{
if (setjmp(&someJumpBuff)) return x;
x++;
someFunction(); // A function that calls longjmp(&someJumpBuff, 1);
x--;
return x;
}
如果没有将x
声明为volatile
,则编译器可以优化x++
和x--
因为它可以假定没有其他代码可以检查这两个操作之间的x
值。 但是, volatile
声明将迫使编译器假定在setjmp
可能在x++
和x--
之间执行后检查x
代码,从而观察此时保持的x
值。
可能会构想一个平台调用约定,在该约定中,对函数定义一无所知的“智能”优化器,除了在参数上未使用volatile
限定符之外,将能够生成不允许在函数中使用的代码。这种限定符的存在,但是即使在这样的平台上,仅看到函数原型缺少volatile
限定符的编译器也没有理由假设其定义不包含一个限定符。
在参数上使用“ volatile”意味着每次使用参数时都要重新读取该参数,而不仅仅是使用以前读取的某个值。
这通常对传递的参数没有用。
“易失性”的时间是某些内容可以与代码执行异步更改的时间,例如在中断或I / O值中修改的内容。
传递的参数是副本,不会异步更改。
“限制”是编码人员对编译器的承诺,即编译器可以忽略某些可能的问题,
例如'I,即编码器,保证对memcpy()的调用的存储区域不会重叠。
因此,仅在相关时使用它们,否则不要使用它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.