Наши партнеры

UnixForum





Библиотека сайта 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).

Если вас интересуют подробные описания упомянутых флагов, вы можете обратиться к странице руководства компилятора GCC.

Кроме того, параметр командной строки -Wextra позволяет компилятору выводить предупреждения в следующих случаях:

  • Указатель сравнивается с целочисленным нулевым значением с помощью оператора <, <=, > или >=.
  • Значения из перечисления и не из перечисления встречаются в одной условной инструкции (только в C++).
  • Отсутствие виртуального наследования от виртуального базового класса (только в C++).
  • Доступ к элементам регистрового массива (только в C++).
  • Получение адреса регистровой переменной (только в C++).
  • Отсутствие инициализации базового класса в рамках конструктора копирования наследуемого класса (только в C++).

Активация предупреждений, связанных со сравнениями значений с плавающей точкой

Вы можете знать о том, что никогда нельзя осуществлять проверку равенства значений с плавающей точкой (если вы не слышали об этом, вам стоит почитать ответы на часто задаваемые вопросы о сравнении значений с плавающей точкой). Но если вы случайно осуществите данную операцию, выведет ли компилятор GCC предупреждение или даже сообщение об ошибке? Давайте проверим.

Это код, в котором осуществляется проверка равенства значений переменных с плавающей точкой с помощью оператора ==:

#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

Если количество параметров командной строки компилятора 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 и вы желаете рассказать о них? Вы можете разместить любую информацию об этих параметрах в разделе комментариев.