Как превратить предупреждения «неявного объявления» в $ CC в ошибки? - PullRequest
9 голосов
/ 11 октября 2011

(Я впервые начал писать программы на C где-то примерно в 1993 году. Тогда времена были другими, компиляторы могли быть другими, но я вспоминаю, что когда кто-то пытается обратиться к функции C, которая не объявлена, он получает ошибку.Кроме того, если функция определена позже, возможно, в другом модуле перевода, и «подписи» не совпадают, то вы получите еще одну ошибку.)

В настоящее время я использую GCC 4.4.3.Я озадачен тем, почему GCC так прощает мне (намеренно в примере) несоответствующее (необязательное) объявление bar и его определение в bar.c, которое, очевидно, приведет к фатальной ошибке адресации - поскольку bar хочетадрес и получает целое число, в конечном итоге он отменяет ссылку на это целое число как адрес.Строгий компилятор, или я так думаю, прервал бы меня с ошибкой.Я что-то пропустил?Моя командная строка сборки выглядит следующим образом:

cc -o foobar -g -Wall -std=c99 -fexec-charset=ISO-8859-1 -DDEBUG foo.c bar.c

С foo.c:

int main()
{
    int a;

    bar(a);

    return 0;
}

и bar.c:

void bar(int * a)
{
    *a = 1;
}

Я намеренно пропустил объявлениеbar, а также намеренно передать ему целое число (может быть что угодно) вместо адреса, как того требует его фактическое определение.Суть для меня такова: поскольку $ (CC) не останавливает меня, я заканчиваю с ошибкой сегментации (x86, Ubuntu 10.04).Я знаю, что совместимый компилятор C (C99?) Неявно создал бы объявление int bar(void) для bar, если ничего не найдено, но в этом случае это явно не то, что я хочу вообще!Я хочу уберечь себя от ошибок, когда я делаю человеческую ошибку, не совмещая объявления и определения или вообще пропуская первые.

Я пытался вместо этого только компилировать - с помощью -c переключателя компилятора - ноэто не имеет значения, поскольку оно все еще успешно с предупреждениями.Хотя компоновщик может раздражать, но я хочу, чтобы компилятор остановил меня до того, как это произойдет.

I на самом деле не хочет превращать мои предупреждения в ошибки, скажем -Werror, потому что:

  • Я мог бы указать неверный float bar(double a); в верхней части foo.c, что полностью исключает предупреждение, но не меняет факт сбоя программы.Увы, программа, которая успешно компилируется без предупреждений (даже с переключателем -Wall) и прекрасно аварийно завершает работу во время выполнения.
  • У меня есть и будут другие типы предупреждений, которые должны оставаться предупреждениями, а не препятствовать успешным сборкам.
  • Это будет иметь дело с эффектом проблемы, а не с самой проблемой
  • Это не только типы предупреждений, но и конкретные случаи.Я бы не хотел превращать конкретный код предупреждения в ошибку, потому что в некоторых случаях это было бы неприменимо.Это было бы слишком грубым решением, которое не учитывает специфику и контекст, в котором произошло предупреждение.

Ответы [ 6 ]

7 голосов
/ 13 марта 2015

Чтобы превратить это предупреждение в ошибку при компиляции с gcc, передайте ключ -Werror=implicit-function-declaration компилятору.

Попытка ответить на вопрос «почему»: да, может показаться странным, что по умолчанию это предупреждение, а не ошибка. Это по историческим причинам. Подробнее см., Например, Почему C разрешил неявные объявления функций и переменных без типов? или прочитал его собственными словами Ричи по адресу http://cm.bell -labs.com / who / dmr / chist.html

4 голосов
/ 11 октября 2011

С GCC документы на предупреждения :

-Понявное-объявление-функции (только C и Objective-C) Предупреждайте всякий раз, когда функция используется перед объявлением. В режиме C99 (-std = c99 или -std = gnu99) это предупреждение включено по умолчанию и преобразуется в ошибку с помощью -pedantic-errors. Это предупреждение также включено -Wall.

...

-pedantic-errors (мой акцент) Как и -pedantic, за исключением того, что ошибки выдаются, а не предупреждения.

...

-pedantic Выпускать все предупреждения, требуемые строгими стандартами ISO C и ISO C ++; отклонить все программы, которые используют запрещенные расширения, и некоторые другие программы, которые не соответствуют ISO C и ISO C ++. Для ISO C следует версии стандарта ISO C, указанной любой используемой опцией -std.

Мне кажется, что -pedantic-errors будет делать то, что вы хотите (превратить эти предупреждения в ошибки), однако похоже, что это также включит множество других проверок, которые вы можете или не хотите. = /

4 голосов
/ 11 октября 2011

Возможно, вы могли бы вызвать дополнительные предупреждения для gcc:

-Wmissing-prototypes
-Wmissing-declarations

Использование обоих (вместе с -Werror), вероятно, поможет вам избежать подобных ситуаций, но потребует еще немного написания кода.

Вдохновленный этим .

РЕДАКТИРОВАТЬ: Пример

// file: mis1.c
int main(void)
{
    int a;

    bar(a);

    return 0;
}

// file: mis2.c
#include <stdio.h>

double bar(double a)
{
    printf("%g\n", a);
    return a;
}

Компиляция с gcc 3.3.4 (DJGPP) как:

gcc -Wall -Wmissing-prototypes -Wmissing-declarations -Werror mis2.c mis1.c -o mis.exe

Выход компилятора:

mis2.c:5: warning: no previous prototype for `bar'
mis1.c: In function `main':
mis1.c:6: warning: implicit declaration of function `bar'

Fix? # Включите в оба файла следующий файл:

// file: mis.h
extern int bar(int);

Перекомпилируя вы получите:

mis2.c:6: error: conflicting types for `bar'
mis.h:3: error: previous declaration of `bar'

Fix? Определите и объявите bar везде одинаково, исправьте, например, mis.h:

// file: mis.h
extern double bar(double);

Аналогично, вы можете изменить bar () в mis2.c, чтобы он соответствовал значению mis.h.

1 голос
/ 16 октября 2011

Наиболее близким к решению моей проблемы было простое использование флага -combine, который косвенно заставляет компилятор прерывать компиляцию при попытке вызвать функцию, в которой отсутствует прототип, или где прототипы не соответствуют или не соответствуютопределение.

Боюсь, у него есть недостатки.Поскольку входные файлы теперь объединяются за один прогон компиляции, в итоге получается один объектный файл, который имеет свои собственные последствия.Короче говоря, -combine делает нечто большее, чем просто решает мою проблему, и это может быть проблемой само по себе.

0 голосов
/ 11 октября 2011
  • Я мог бы включить неправильный бар-поплавок (удвоить a); вверху foo.c, который полностью исключает предупреждение, но не меняет
    Дело в том, что получающаяся программа вылетает. Увы, программа, которая
    успешно компилируется без предупреждений (даже с ключом -Wall)
    и красиво вылетает во время выполнения.

Поэтому важно, помимо других мер, включить тот же заголовочный файл (включая прототип) в foo.c и bar.c. Это гарантирует, что правильный прототип применяется в обоих местах.

0 голосов
/ 11 октября 2011

Вы можете превратить все предупреждения в ошибки с помощью

cc [..] -Werror [..]

. Это частично решит вашу проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...