Почему существуют разные определения INT64_MIN? И почему они ведут себя по-разному?

Заголовок stdint.h в моей компании гласит:

#define INT64_MIN -9223372036854775808LL

Но в каком-то коде моего проекта программист написал:

#undef INT64_MIN
#define INT64_MIN (-9223372036854775807LL -1)

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

error: integer constant is so large that it is unsigned

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


person abelenky    schedule 29.06.2012    source источник
comment
Не страшно ли, что #define из стандартного заголовочного файла вызывает ошибку?   -  person fvu    schedule 30.06.2012
comment
@fvu: все в порядке, оказывается, проблема в том, что работодатель abelenky заменил стандартный заголовок своей собственной неработающей версией (см. Комментарии ниже).   -  person Steve Jessop    schedule 30.06.2012
comment
@SteveJessop Я видел это в обсуждении. По-моему, идея с довольно заячьими мозгами.   -  person fvu    schedule 30.06.2012


Ответы (1)


-9223372036854775808LL не является одним литералом. Это выражение, состоящее из унарного оператора -, примененного к константе 9223372036854775808LL.

Эта константа (едва ли) выходит за пределы диапазона типа long long, что вызывает предупреждение. (Я предполагаю, что long long — это 64 бита, что почти наверняка так и есть.)

Выражение (-9223372036854775807LL -1), с другой стороны, содержит литералы, которые находятся в диапазоне long long, и является в равной степени более подходящим определением для INT64_MIN, поскольку оно имеет правильный тип (как указывает Стив Джессоп в комментарий).

person Keith Thompson    schedule 29.06.2012
comment
Хорошее объяснение. Означает ли это, что определение в stdint.h неверно, поскольку оно использует значение вне диапазона LL? - person abelenky; 30.06.2012
comment
@abelenky: Не обязательно. Пока он дает правильное поведение для компилятора, с которым он предназначен, все в порядке. Даже если он выдает ложное предупреждение, это не делает его несоответствующим, хотя я все равно считаю это ошибкой. Обратите внимание, что <stdint.h> в моей системе использует прием -1. В какой системе вы работаете и откуда взялся ваш <stdint.h>? - person Keith Thompson; 30.06.2012
comment
У меня 64-битная система Linux. stdint.h взят из исходного репозитория компании. Я склонен предполагать, что у него есть некоторый опыт работы с Unix, но я не знаю подробностей его истории. - person abelenky; 30.06.2012
comment
@abelenky: Почему ваша компания предоставляет свои собственные <stdint.h>? Он должен быть предоставлен вашим компилятором или библиотекой времени выполнения. В любой системе Linux это предоставляется glibc. - person Keith Thompson; 30.06.2012
comment
Почему моя компания делает большую часть того, что делает? Это все равно, что спросить квадратный корень из миллиона; никто никогда не узнает - Нельсон Манц. Это просто наш кодекс, и я не босс. - person abelenky; 30.06.2012
comment
@Keith: 7.18.2 из C99 говорит о INT64_MIN, это выражение должно иметь тот же тип, что и выражение, которое является объектом соответствующего типа, преобразованным в соответствии с целочисленными акциями. Таким образом, ваше определение является более верным, чем определение работодателя, задавшего вопросы, но не столь же верным: тип INT64_MIN должен быть int64_t, а не uint64_t. Выражение с неправильным типом не может иметь правильное поведение для компилятора, с которым оно предназначено для использования, в случае, если кто-то напишет if (INT64_MIN > 0) .... Но на многих/большинстве компиляторов ((long long)-922 etc) будет нормально. - person Steve Jessop; 30.06.2012