2014-02-19 3 views
1

я сделал следующий C эксперимент: У меня есть три файла (переменного тока, ах, Ьс):Синтаксис C: Является ли следующее «extern volatile const» поведение последовательным среди компиляторов C?

  • переменного тока:

    #define _A_C_ 
    #include "a.h" 
    #undef _A_C_ 
    
    #include <stdio.h> 
    
    int v = 19; // some value 
    void 
    fa() 
    { 
         printf("a.c: v = %d\n", v); 
    } 
    
  • ах:

    #ifndef _A_H_ 
    #define _A_H_ 
    
    #ifndef _A_C_ 
        // before edit the following line was 'extern const int v;' 
        extern volatile const int v; 
    #endif 
    
    void 
    fa(); 
    
    #endif 
    
  • b.c:

    #include "a.h" 
    #include <stdio.h> 
    
    void 
    fb() 
    { 
        printf("b.c: v = %d\n", v); 
         //v = 5; // -> uncomment this and you will get a compile error 
    } 
    
    int 
    main() 
    { 
        fa(); 
        fb(); 
        getch(); 
        return 0; 
    } 
    

То, что я хочу получить с этим, чтобы иметь возможность изменять переменную выборочно.

Так в основном, v будет рассматриваться как int для a.c и, как const int для остальной части кода (например b.c).

С GCC 4.8.1 это ссылки и ведет себя, как и ожидалось.

Я хочу знать, могу ли я полагаться на это поведение в компиляторах C.

Спасибо

EDIT

Благодаря Pascal Cuoq, я понял, что extern const int v; в ах должен быть изменен, чтобы extern volatile const int v; избежать оптимизации компилятора выдает

Другие факты

  • где extern const x синтаксический действует, const x ВЫЗОВЕТ й экспортироваться как символ в результирующем объектном файле
  • , таким образом, еще один эквивалент вопроса на самом деле: есть ли случай, когда экспортированный символ const int xбудет отличаться в итоговый файл объекта, чем int x? (Например, это COFF разрешает это?)
+0

@hivert внимательно прочитайте, это не тот же вопрос; в основном в сообщении, отмеченном как ответ на этот вопрос, ответчик говорит: «И да, он должен точно соответствовать объявлению в блоке перевода, на котором он фактически объявлен. Если, конечно, вы не участвуете в конкурсе Underhanded C Programming :-)». Я только что продемонстрировал, что нашел способ избежать этого наложения и спросил, могу ли я положиться на него. –

+1

plus, связанный пост относится к C++, а не C –

+1

вопрос кажется мне законным – Bruce

ответ

2

v будет рассматриваться как int для a.c и, как const int для остальной части кода (например, b.c).

Рассмотрит функцию:

extern int v = 5; 

int main() 
{ 
    f(); 
    return v; 
} 

GCC будет счастливо оптимизации функции выше { f(); return 5; }. Если f() происходит из файла, где v не является const и фактически изменяет v, функция main() будет выглядеть не так, как ожидалось.

Так что в заключение это запрещено стандартом, и на самом деле он фактически нарушает программы на практике.

EDIT: если вы надеетесь, что не обеспечивает инициализатор для const декларации поможет, рассмотреть следующие вопросы:

На самом деле нет никакой ссылки на x вообще в файле сборки. Он может быть связан с другими файлами, один из которых предоставляет f и никогда не жалуется, что отсутствует x, а тем более что он имеет неправильный тип.

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

+0

, поэтому в a.h v НЕ будет инициализироваться. –

+0

@Zuzel Ответ отредактирован после вашего комментария. –

+0

спасибо, я проверил это, и вы правы; Кроме того, добавление изменчивости в «extern const int a» (как в «extern volatile const int a» также устраняет эту проблему, отредактировал мой вопрос с этой целью –

1

Даже если x не инициализирован в своей внешней декларации, компилятор может считать, что два вхождения x в двух разных операторах равны. Если рассмотреть следующий пример

extern const int x; 

extern void f(void); 

int main() { 
    const int y = x; 
    f(); 
    return y-x; 
} 

с x и f определен в другом файле, как например:

int x = 5; 

void f() { x = 4; } 

и компилирует с gcc -O1, вы получите программу, в которой выход значение 0, в то время как -O0 будет дайте вам 1. Другими словами, заключение Паскаля Куока является правильным.