Что такое "int i = 1; почему (i> = 60 * 60 * 1000/1 * 1000)" верно? - PullRequest
37 голосов
/ 14 июля 2011

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

#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

Ответы [ 9 ]

69 голосов
/ 14 июля 2011

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

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

42 голосов
/ 14 июля 2011

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

Чтобы добиться желаемого, поставьте ():

#define BIG_INTERVAL (60 * 60 * 1000)
#define SMALL_INTERVAL (1 * 1000)
12 голосов
/ 14 июля 2011

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

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

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

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

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

9 голосов
/ 14 июля 2011

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

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

4 голосов
/ 14 июля 2011

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

2 голосов
/ 14 июля 2011

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

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

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

1 голос
/ 14 июля 2011

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

1 голос
/ 14 июля 2011

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

0 голосов
/ 07 августа 2011

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

Вопрос имеет:

#define BIG_INTERVAL 60 * 60 * 1000

(иОпрашивающий признает, что отсутствие скобок является проблемой).Но даже с:

#define BIG_INTERVAL (60 * 60 * 1000)

каждая из констант (60, 60 и 1000) определенно представляется как целое число, но продукт равен 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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...