Почему я получаю предупреждение при использовании переменной int, а не при использовании целочисленной константы? - PullRequest
4 голосов
/ 10 марта 2020

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

1. код :

#include <stdio.h>

int main()
{
    int var = 24;

    if((!var) == NULL)
    {
        printf("1");
    }
}

2. код :

#include <stdio.h>

int main()
{
    if((!24) == NULL)
    {
        printf("1");
    }
}

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

предупреждение: сравнение между указателем и целым числом

от g cc и

предупреждение: сравнение между указателем и целым числом ('int' и 'void *') [-Wpointer-integer-compare]

из clang.

Когда я компилирую почти эквивалентный код, используя то же значение, что и целочисленная константа, все в порядке. Почему?


Мои исследования до сих пор:

Я изучил C18 и обнаружил в разделе 6.4.4 «Константы»:

Сначала в подразделе / ​​2 и / 3:

" 2 - каждая константа должна иметь тип, а значение константы должно находиться в диапазоне представимых значений для ее типа. "

" 3 - У каждой константы есть тип, определяемый ее формой и значением, как описано позже. ".

И второй в подразделе / ​​5:

" Тип целочисленной константы является первым из соответствующего списка, в котором может быть представлено ее значение. "

Следующий список:

list

Таким образом, целочисленная константа без суффикса относительно представимого значения 24 должна иметь тип int.


Я понимаю само предупреждение и знаю, что NULL обычно в большинстве реализаций расширяется до (void*) 0. Таким образом, разумно, что это предупреждение выдается.

Но почему предупреждение не возникает при использовании того же значения, что и целочисленная константа?

1 Ответ

6 голосов
/ 10 марта 2020

Из C11 6.3.2.3/3:

Целочисленное константное выражение со значением 0 или такое выражение, приведенное к типу void *, называется константой нулевого указателя.

И из 6.5.9 / 2 относительно операторов равенства == и !=:

Должно выполняться одно из следующего:
...
- один операнд - это указатель, а другой - константа с нулевым указателем.

Обратите внимание, что выражения с целочисленными константами не ограничиваются целочисленными константами (0, 42 и т. д. c.), но также могут включать в себя операторы, действующие на них, например, 5+5-10.

!24 является выражением целочисленной константы со значением 0 и, следовательно, считается константой нулевого указателя. Оператору == разрешено действовать между указателем и константой нулевого указателя, что делает (!24) == NULL допустимым сравнением.

В вашем первом примере !var не является целочисленным константным выражением, поскольку оно включает в себя переменный операнд, и, следовательно, его нельзя сравнивать с указателем.

Предостережение: в большинстве реализаций NULL определяется как (void*)0, и приведенное выше является правильным. Тем не менее, стандарт позволяет определять его как любую константу нулевого указателя, например 0. Если это так, то сравнение (!var) == NULL будет скомпилировано, поскольку оно совпадает с (!var) == 0.

...