Что такое "int я = 1: Why (i >= 60 * 60 * 1000/1 * 1000)" true?

Во-первых, определение двух постоянных выражений без круглых скобок - это моя ошибка:

#define BIG_INTERVAL 60 * 60 * 1000
#define SMALL_INTERVAL 1 * 1000

int i = 1;

if (i >= BIG_INTERVAL / SMALL_INTERVAL - 1)
{
    printf("Oops!\n");
}

Оператор if после расширения макроса if(i >= 60 * 60 * 1000 / 1 * 1000 - 1).

Это не мое намерение. Но я нахожу что-то странное, если пишу if (i >= 3600000000 - 1). Это неверно.

Какой тип 60 * 60 * 1000 / 1 * 1000 - 1? int?

Ответ 1

Все операторы на int возвращают int. Итак, 60 * 60 * 1000 / 1 * 1000 - 1 - int. Но ожидаемый результат 3599999999 слишком велик для int, поэтому выражение действительно оценивает -694967297 (предполагая 32-разрядный int и два дополнения).

Это не происходит с литералом 3600000000, потому что целочисленные литералы, превышающие INT_MAX, имеют тип, который может содержать полное значение.

Ответ 2

60 * 60 * 1000/1 * 1000 - 1 = 3600000 * 1000 - 1, который переполняет тип int, поэтому результат может быть любым (в вашем случае он отрицательный, но это не обязательно).

Чтобы добиться того, что вы хотите поставить():

#define BIG_INTERVAL (60 * 60 * 1000)
#define SMALL_INTERVAL (1 * 1000)

Ответ 3

Здесь мои результаты теста:

60 * 60 * 1000 / 1 * 1000 will result to -694967296

(60 * 60 * 1000) / (1*1000) will result to 3600

Там проблема с вашей работой, приоритет вычислений.

Возможно, вам стоит взглянуть на приоритет оператора С++ http://msdn.microsoft.com/en-us/library/126fe14k%28v=vs.80%29.aspx. Вы найдете причину, по которой результатом стал -694967296, который, как мне кажется, влияет на переполнение.

Ответ 4

Если вы используете компилятор, где int - 64 бита, вы обнаружите, что результат вашего выражения является ложным. Если вы используете компилятор, где int 32 бит или 16 бит, ваше выражение имеет поведение undefined, потому что переполнение подписанных ints не нужно обертывать. Вероятно, вы просто обернули, но это не обязательно.

3600000000 - это постоянная видимость во время компиляции, поэтому, если int всего 32 бита, то вашему компилятору придется выбирать длинный длинный (или просто длинный, если длинный - 64 бит). Таким образом, ваше другое выражение оценивается с достаточным количеством бит, чтобы избежать переполнения, и результат правильный.

Ответ 5

Может быть, вы переполняете размер int, который составляет 2147 м или около того, что означает, что если вы перейдете к представлению, это станет отрицательным. Как указывалось другими ответами, разделение ничего не делает при расширении, поэтому окружающие макроопределения заключаются в круглые скобки

Ответ 6

Вы, скорее всего, выходите за пределы допустимого диапазона значений для подписанного int - 3600000000 - это довольно большое число!

Когда это произойдет, значение станет наименьшим отрицательным значением для типа данных int.

Это приведет к тому, что ваше утверждение будет истинным.

Ответ 7

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

Ответ 8

Я думаю, вы смущены тем, как работают макросы. Вы не используете значения этих макросов, а сами уравнения. Я думаю, что это была твоя путаница. Я думаю, вы должны скопировать в свои макросы или не использовать макросы.

Ответ 9

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

Вопрос:

#define BIG_INTERVAL 60 * 60 * 1000

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

#define BIG_INTERVAL (60 * 60 * 1000)

каждая из констант (60, 60 и 1000) определенно представляется в виде int, но продукт 3600000, тогда как язык только гарантирует, что INT_MAX >= 32767.

Язык говорит, что большие целочисленные константы имеют тип, достаточно большой для хранения своих значений (например, 100000 может быть либо типа int, либо типа long int, в зависимости от диапазонов этих типов), но он не имеет такого правила для выражений, даже постоянных выражений.

Вы можете обойти это следующим образом:

#define BIG_INTERVAL (60L * 60L * 1000L)

но это делает его типом long, даже если это не нужно.

Что касается проблемы приоритета оператора, вот мой любимый пример:

#include <stdio.h>

#define SIX 1+5
#define NINE 8+1

int main(void)
{
    printf("%d * %d = %d\n", SIX, NINE, SIX * NINE);
    return 0;
}

Выход, конечно,

6 * 9 = 42

(см. Дуглас Адамс).