Библиотека сайта rus-linux.net
Малоизвестные полезные параметры компилятора GCC - часть 2
Оригинал: Uncommon but useful GCC command line options - part 2
Автор: Himanshu Arora
Дата публикации: 1 декабря 2016 г.
Перевод: А.Панин
Дата перевода: 8 февраля 2017 г.
Компилятор GCC поддерживает на первый взгляд бесконечное количество параметров командной строки. Конечно же, никто не использует и не изучает все эти параметры в процессе работы над своим программным обеспечением, но существует ряд параметров, о которых должен, а может быть и обязан знать каждый разработчик. Некоторые из этих параметров могут использоваться достаточно часто, другие - от случая к случаю, что, впрочем, не делает их менее полезными.
В рамках данной серии статей мы рассматриваем некоторые из этих малоизвестных, но полезных параметров командной строки компилятора GCC и уже обсудили пару таких параметров в первой статье.
Если вы помните, в начале первой статьи серии я кратко упоминал о том, что параметр -Wall
, который обычно используется разработчиками для генерации предупреждений, не позволяет генерировать некоторые специфические предупреждения. Если вы никогда не слышали об этих предупреждениях и методике их активации, вы можете не волноваться, так как мы подробно обсудим их в рамках данной статьи.
Кроме того, мы также обсудим параметры командной строки компилятора GCC для вывода предупреждений, связанных с переменными с плавающей точкой, а также обратим внимание на оптимальную методику работы с большим количеством параметров командной строки компилятора GCC.
Но перед тем, как перейти к рассмотрению обозначенных выше вопросов, следует упомянуть о том, что все примеры, команды и инструкции из данной статьи были протестированы в системе Ubuntu 16.04 LTS с компилятором GCC версии 5.4.0.
Активация вывода предупреждений, не связанных с параметром -Wall
Хотя параметр командной строки -Wall
и сообщает компилятору GCC о необходимости вывода подавляющего большинства предупреждений, некоторые предупреждения не выводятся даже при использовании данного параметра. Для их вывода следует использовать параметр -Wextra
.
В качестве примера предлагаю рассмотреть следующий код:
#include <stdio.h> #include <stdlib.h> int main() { int i=0; /* ... основной код ... */ if(i); return 1; return 0; }
Я случайно разместил символ точки с запятой после условной инструкции if
. При последующей компиляции кода с помощью приведенной ниже команды компилятор GCC не выведет каких-либо предупреждений:
gcc -Wall test.c -o test
А теперь рассмотрим случай использования параметра -Wextra
:
gcc -Wall -Wextra test.c -o test
В этом случае будет выведено аналогичное предупреждение:
test.c: In function ‘main’: test.c:10:8: warning: suggest braces around empty body in an ‘if’ statement [-Wempty-body] if(i);
Из приведенного выше текста предупреждения очевидно, что использование параметра командной строки -Wextra
привело к активации флага компилятора -Wempty-body
, в результате чего был выявлен подозрительный фрагмент кода и выведено соответствующее предупреждение. А это полный список флагов предупреждений, активируемых с помощью рассматриваемого параметра командной строки: -Wclobbered
, -Wempty-body
, -Wignored-qualifiers
, -Wmissing-field-initializers
, -Wmissing-parameter-type
(только для языка C), -Wold-style-declaration
(только для языка C), -Woverride-init
, -Wsign-compare
, -Wtype-limits
, -Wuninitialized
, -Wunused-parameter
(только при использовании с -Wunused
или -Wall
) и -Wunused-but-set-parameter
(только при использовании с -Wunused
или -Wall
).
Если вас интересуют подробные описания упомянутых флагов, вы можете обратиться к
Кроме того, параметр командной строки -Wextra
позволяет компилятору выводить предупреждения в следующих случаях:
- Указатель сравнивается с целочисленным нулевым значением с помощью оператора <, <=, > или >=.
- Значения из перечисления и не из перечисления встречаются в одной условной инструкции (только в C++).
- Отсутствие виртуального наследования от виртуального базового класса (только в C++).
- Доступ к элементам регистрового массива (только в C++).
- Получение адреса регистровой переменной (только в C++).
- Отсутствие инициализации базового класса в рамках конструктора копирования наследуемого класса (только в C++).
Активация предупреждений, связанных со сравнениями значений с плавающей точкой
Вы можете знать о том, что никогда нельзя осуществлять проверку равенства значений с плавающей точкой (если вы не слышали об этом, вам стоит почитать
Это код, в котором осуществляется проверка равенства значений переменных с плавающей точкой с помощью оператора ==
:
#include <stdio.h> void compare(float x, float y) { if(x == y) { printf("\n РАВНЫ \n"); } } int main(void) { compare(1.234, 1.56789); return 0; }
А это команда компиляции данного кода с помощью компилятора GCC (содержащая как параметр -Wall
, так и параметр -Wextra
):
gcc -Wall -Wextra test.c -o test
К сожалению, в процессе исполнения данной команды не будет выведено каких-либо предупреждений, связанных со сравнением значений с плавающей точкой. Быстрый просмотр страницы руководства GCC позволяет обнаружить наличие отдельного параметра командной строки -Wfloat-equal
, который должен использоваться в подобных сценариях.
А это команда с данным параметром:
gcc -Wall -Wextra -Wfloat-equal test.c -o test
Данная команда позволяет сгенерировать аналогичный вывод:
test.c: In function ‘compare’: test.c:5:10: warning: comparing floating point with == or != is unsafe [-Wfloat-equal] if(x == y)
Как несложно обнаружить, параметр -Wfloat-equal
сообщает компилятору GCC о необходимости генерации предупреждения, связанного со сравнением чисел с плавающей точкой.
А это выдержка из описания данного параметра на
Данная операция нередко используется по той причине, что программисту удобнее считать значения с плавающей точкой бесконечно точными аппроксимацями дробных чисел. Если вы также прибегаете к ней, вам придется вычислить (путем анализа кода или каким-либо другим образом) максимальную или возможную максимальную погрешность расчета и учесть ее в процессе сравнения значений (а также их вывода, но это уже другая операция). По сути, вместо установления равенства значений вам придется установить, пересекаются ли диапазоны этих двух значений; а для этой цели должны использоваться операторы сравнения, поэтому использование оператора равенства является, скорее всего, плохой практикой.
Оптимальная работа с параметрами командной строки компилятора GCC
Если количество параметров командной строки компилятора GCC в вашем проекте стало настолько большим, что вам неудобно ими управлять, вы можете разместить эти параметры в текстовом файле и передать компилятору имя этого текстового файла в качестве параметра командной строки. Для этой цели должен использоваться специальный параметр командной строки @file
.
Например, если ваша команда компиляции выглядит следующим образом:
gcc -Wall -Wextra -Wfloat-equal test.c -o test
То вы можете разместить три связанных с выводом предупреждений параметра в файле с именем, таким, как gcc-options
:
$ cat gcc-options -Wall -Wextra -Wfloat-equal
После чего ваша команда компиляции станет более простой и доступной для редактирования:
gcc @gcc-options test.c -o test
А это выдержка из описания параметра @file
со страницы руководства компилятора GCC:
Чтение параметров командной строки из файла. Параметры читаются и подставляются вместо параметра @file
. Если файла с переданным именем не существует или этот файл не может быть прочитан, параметр будет обработан таким же образом, как и все другие параметры, а не удален.
Параметры в файле должны разделяться с помощью символов пробелов. Символ пробела может быть включен в состав параметра путем помещения этого параметра в одинарные или двойные кавычки. Любой символ (включая обратный слэш) может быть включен в состав параметра путем помещения перед этим символом обратного слэша. Сам файл может содержать дополнительные параметры @file
; все эти параметры будут рекурсивно обрабатываться.
Заключение
На данный момент мы рассмотрели пять малоизвестных полезных параметров компилятора GCC: -save-temps
, -g
, -Wextra
, -Wfloat-equal
и @file
. Потратьте немного своего времени на их испытание и не забудьте прочитать описание каждого из них на странице руководства компилятора GCC.
Вам знакомы другие подобные параметры командной строки компилятора GCC и вы желаете рассказать о них? Вы можете разместить любую информацию об этих параметрах в разделе комментариев.