Поиск…


Сравнение литералов и переменных

Предположим, что вы сравниваете значение с некоторой переменной

if ( i  == 2) //Bad-way
{
    doSomething;
}

Теперь предположим, что вы ошибаетесь == с = . Тогда вам понадобится ваше сладкое время, чтобы понять это.

if( 2 == i) //Good-way
{
    doSomething;
}

Затем, если знак равенства случайно исключен, компилятор будет жаловаться на «попытку присвоения литералу». Это не будет защищать вас при сравнении двух переменных, но каждый бит помогает.

См. Здесь для получения дополнительной информации.

Не оставляйте список параметров функции пустым - используйте void

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

  • У вас есть выбор: сохранить список параметров пустым как для прототипа, так и для определения. Таким образом, они выглядят так же, как и запрос вызова функции.

  • Вы где-то читали, что одно из применений ключевого слова void (их всего несколько) - это определение списка параметров функций, которые не принимают никаких аргументов в их вызове. Таким образом, это тоже выбор.

Итак, что является правильным выбором?

ОТВЕТ: использование ключевого слова void

ОБЩИЕ КОНСУЛЬТАЦИИ: Если язык предоставляет определенную функцию для использования в специальных целях, вам лучше использовать это в своем коде. Например, используя enum s вместо #define макросов (это для другого примера).

Раздел C11 6.7.6.3 В пункте 10 «Деклараторы функций» говорится:

Частный случай неименованного параметра типа void как единственного элемента в списке указывает, что функция не имеет параметров.

Параграф 14 этого же раздела показывает единственную разницу:

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

Упрощенное объяснение, представленное K & R (pgs-72-73) для вышеуказанного материала:

Кроме того, если объявление функции не содержит аргументов, как в
double atof(); , это тоже означает, что ничего не следует предполагать в отношении аргументов atof ; вся проверка параметров отключена. Это специальное значение пустого списка аргументов предназначено для того, чтобы более старые программы на C могли компилироваться с новыми компиляторами. Но это плохая идея использовать его с новыми программами. Если функция принимает аргументы, объявляйте их; если он не принимает аргументов, используйте void .

Так вот как должен выглядеть ваш прототип функции:

int foo(void);

И так должно быть определение функции:

int foo(void)
{
    ...
    <statements>
    ...
    return 1;
}

Одно из преимуществ использования выше, над объявлением типа int foo() (т. Е. Без использования ключевого слова void ) заключается в том, что компилятор может обнаружить ошибку, если вы вызываете свою функцию, используя ошибочное утверждение, например foo(42) . Такой тип выражения вызова функции не вызывает никаких ошибок, если оставить список параметров пустым. Ошибка будет проходить молча, незаметно, и код все равно будет выполняться.

Это также означает, что вы должны определить функцию main() следующим образом:

int main(void)
{
    ...
    <statements>
    ...
    return 0;
}

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

#include <stdio.h>

static void parameterless()
{
    printf("%s called\n", __func__);
}

int main(void)
{
    parameterless(3, "arguments", "provided");
    return 0;
}

Если этот код сохраняется в файле proto79.c , его можно скомпилировать в Unix с GCC (версия 7.1.0 на macOS Sierra 10.12.5, используемая для демонстрации), например:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -pedantic proto79.c -o proto79
$

Если вы скомпилируете более строгие параметры, вы получите ошибки:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -pedantic proto79.c -o proto79 
proto79.c:3:13: error: function declaration isn’t a prototype [-Werror=strict-prototypes]
 static void parameterless()
             ^~~~~~~~~~~~~
proto79.c: In function ‘parameterless’:
proto79.c:3:13: error: old-style function definition [-Werror=old-style-definition]
cc1: all warnings being treated as errors
$

Если вы даете функции формальный прототип static void parameterless(void) , то компиляция дает ошибки:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -pedantic proto79.c -o proto79 
proto79.c: In function ‘main’:
proto79.c:10:5: error: too many arguments to function ‘parameterless’
     parameterless(3, "arguments", "provided");
     ^~~~~~~~~~~~~
proto79.c:3:13: note: declared here
 static void parameterless(void)
             ^~~~~~~~~~~~~
$

Мораль - всегда убедитесь, что у вас есть прототипы, и убедитесь, что ваш компилятор говорит вам, когда вы не соблюдаете правила.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow