2015-03-02 3 views
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 это явно спорный вопрос; однако в случае 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;?

(Related question)

+0

Я не думаю, что последнее предложение, о котором вы говорите, относится ко всему абзацу 15, оно только применяется к только что предшествующей фразе. Вначале ясно сказано, что * соответствующие параметры должны иметь совместимых типов *, поэтому для определения прототипа функции необходимо определить параметры. –

+1

@JensGustedt, поэтому вы говорите, что 'void f (int); void f (int const); int main() {} 'плохо сформирован? –

+0

Игнорируя здравый смысл, единственное, что каким-то образом может определить ограниченное определение UB, которое я нахожу в настоящее время, это 6.2.7. P2. Все объявления, относящиеся к одному и тому же объекту или функции, должны иметь совместимый тип; в противном случае поведение не определено. Но это неправедно абсурдно: оно будет одинаково применимо к 'const' (скажем, ABI, используя другой способ передачи аргументов' const'), и это создаст 'void f (const int * restrict); 'different, так как нет' p', который объявлен в первую очередь (поэтому нет объявления). – mafso

ответ

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 

Если я скомпилировать его с помощью аннулируются F (сопзЬ Int * __ restrict__ р) я получаю

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, наконец, если я скомпилировать его с помощью аннулируются F (сопзЬ Int * __ volatile__ р) я получаю

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.

+0

не существует способа узнать, является ли такой короткий код. – HuStmpHrrr

+1

Это чистый вопрос юриста. Какие компиляторы сейчас делают и что они могут сделать в какой-то момент в будущем, это две разные вещи. – mafso

-1

Использование «volatile» по параметру означает перечитать параметр каждый раз, когда он используется, а не просто использовать некоторое ранее прочитанное значение.

Это «обычно» бесполезно по переданному параметру.

Время для «volatile» - это то, что что-то может измениться асинхронно на выполнение кода, например, что-то изменилось при прерывании или значении ввода-вывода.

Прошедшие параметры являются копиями и не изменяются асинхронно.

«Ограничить» обещание кодера, компилятор, что некоторые возможные проблемы могут быть проигнорированы компилятором,

, такими как «Я, кодировщик, обещаю, что области памяти этого вызова к memcpy() не перекрываются.

Так просто используйте их, когда они актуальны, и не используйте их в противном случае.

+0

Я не вижу, как это пытается ответить на вопрос –

1

Предполагая определение f, не имеющее квалификатора restrict, код должен быть четко определен. C11 (n1570) 6.5.2.2 (вызовы функций) p7 [emph. мой, идентичные формулировки в C99 ТС3 (n1256)]

Если выражение, которое обозначает вызываемой функции имеет тип, который действительно включает прототип, аргументы неявно преобразуются, как по заданию, к типам соответствующие параметры, , беря тип каждого параметра в качестве неквалифицированной версии объявленного типа.

Функция f вызываются с неквалифицированными аргументами (и, таким образом, с аргументами правильных типов), и все его заявления имеют совместимый типа (согласно цитате в вопросе): Вызов функции является хорошо определены. (Если в стандарте нет ничего, что явно не определено). Я не думаю, что есть.)

+0

Пример кода хорошо сформирован, но вопрос в том, может ли оптимизатор предположить, что 'f (p);' не изменяет 'a'. –

+0

Я думаю, что ваша цитата может пойти навстречу вопросу (указывая, что квалификаторы удаляются при вызове функции). –

+0

@MattMcNabb: Я думал, что единственное, что нужно показать, это то, должно ли определение 'f' также иметь свой параметр, объявленный' ограничивать', а не если 'f' может изменить' * p'. Вы правы в том, что последнее не совсем ясно из моего ответа. Я обдумаю это снова ... – mafso

Смежные вопросы