4

次のプロトタイプ間に実際的な違いはありますか?

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することで、コンパイラはaforの読み取りを最適化できreturn a;ますか?

(関連する質問)

4

4 に答える 4

1

修飾子がfないという定義を想定すると、コードは明確に定義されている必要があります。restrictC11 (n1570) 6.5.2.2 (関数呼び出し) p7 [emph. 私の場合、C99 TC3 (n1256) と同じ文言]

呼び出された関数を示す式がプロトタイプを含まない型を持っている場合、引数は、割り当てによるかのように、対応するパラメーターの型に暗黙的に変換され、各パラメーターの型が宣言された型の非修飾バージョンになります。タイプ

関数fは修飾されていない引数 (したがって、正しい型の引数) で呼び出され、すべての宣言は互換性のある型です (質問の引用に従って): 関数呼び出しは明確に定義されています。(標準に明示的に未定義にするものがない場合。私はそうは思わない。)

于 2015-03-03T18:08:07.447 に答える
1

標準に何もない場合は、コンパイラ次第ですが、少なくとも 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 でも無視されているようです。

于 2015-03-02T21:59:17.747 に答える