繁体   English   中英

在函数原型中,顶级volatile或strict是否重要?

[英]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这显然没有意义; 但是,在volatilerestrict的情况下,可能会有所不同。

例:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM