Стандарты C11 говорят о связи идентификаторов, но нет очевидной дискуссии о правилах связывания единиц перевода. Мой вопрос воспитывается путем составления двух простых примеров с использованием clang.Каковы правила связывания единиц перевода в C11?
Вот мой первый пример, который имеет два объявления одной и ту же функцию, но с несовместимыми типами:
//testall.c
extern char myfun(void*);
int main(){
char a='c';
a=myfun(&a);
}
char myfun(char*c){
return *c;
}
Затем я запустить команду: $ лязга -std = C11 testall.c
И звон отчетов Ошибка:
testall.c:9:10: error: conflicting types for 'myfun'
char myfun(char*c){
^
testall.c:2:17: note: previous declaration is here
extern char myfun(void*);
^
1 error generated.
Я понимаю эту ошибку, поскольку указатель на указатель и указатель на символ несовместимы.
Что меня смущает, что когда я разделить два объявления в двух разных единицах трансляции, а затем соединить их в одно целое, лязг не сообщает об ошибке:
//test.c
extern char myfun(void*);
int main(){
char a='c';
a=myfun(&a);
}
// mylib.c
char myfun(char*c){
return *c;
}
Затем я выполнить эту команду: $ лязг -std = c11 test.c mylib.c.
clang компилирует и связывает два блока перевода без сообщения об ошибке или предупреждении.
Я думал, что связывание двух единиц перевода следует правилам в разделе 6.2.2 Связи идентификаторов стандартов C11. Но, похоже, это не так. Может ли кто-нибудь помочь мне прояснить это?
Просто потому, что вы не получаете диагностику, это не значит, что код является законным! Традиционно компилятор просматривает только одну единицу перевода за раз (поэтому он не смог обнаружить несоответствие при компиляции), а информация типа не передается в объектный файл, поэтому компоновщик не сможет обнаружить несоответствие или. –
@NateEldredge Попробуйте сделать один файл за раз, а не указывая оба в командной строке. Выполнение 'gcc a.c b.c' выполняет компиляцию и соединение за один шаг. C не работает с именем, так что имена функции выглядят точно так же, как и для компоновщика. Теперь, что, если у вас есть три объектных файла с 'myfun'? Вы получите ошибку переопределения функции. Так ясно, что вы сказали, не может быть правдой. –
Хотя 'gcc a.c b.c' запускает как компилятор, так и компоновщик, они представляют собой два отдельных прохода, которые не обмениваются информацией, отличной от объектного. Линкер способен обнаруживать несколько ** определений ** одного и того же символа. Но в вашем примере функция 'myfun' определяется ** только **, в' mylib.c'. Файл 'test.c' содержит ** декларацию **' myfun', но не ** определение **. Следовательно, нет ошибки в компоновщике. –