Int overflow (простой вопрос)
От: Посторонним В. Беларусь  
Дата: 16.12.06 21:42
Оценка:
Пожалуйста объясните (со ссылкой на стандарт или авторитетов вроде Страуструпа) что должен напечатать след. код
    short s = SHRT_MAX + 1;
    int i = INT_MAX + 1;
    cout << ++s << endl;
    cout << ++i << endl;
Re: Int overflow (простой вопрос)
От: Андрей Тарасевич Беларусь  
Дата: 16.12.06 22:36
Оценка: 63 (6)
Здравствуйте, Посторонним В., Вы писали:

ПВ>Пожалуйста объясните (со ссылкой на стандарт или авторитетов вроде Страуструпа) что должен напечатать след. код

ПВ>
ПВ>    short s = SHRT_MAX + 1;
ПВ>    int i = INT_MAX + 1;
ПВ>    cout << ++s << endl;
ПВ>    cout << ++i << endl;
ПВ>


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

Сначала рассмотрим то, что связано с переменной 'i'. Тут все просто: в процессе инициализации 'i' производится вычисление выражения 'INT_MAX + 1'. Это выражение вычисляется в рамках типа 'int' и приводит к переполнению, т.к. значение 'INT_MAX + 1' не помещается в диапазон значений типа 'int'. Это приводит к неопределенному поведению (см. 5/5). Т.е. неопределенное поведение в этом случае возникает еще в процессе вычисления выражения 'INT_MAX + 1'. До инициализации собственно 'i' (и, тем более, до инкремента и печати 'i') дело даже может и не дойти. Рассматривать ситуацию с 'i' дальше смысла не имеет.

Теперь 's'. Сначала будет производитьcя вычисление выражения 'SHRT_MAX + 1' и делаться это будет в рамках типа 'int'. Тут возможны два варианта,
в зависимости от того, как соотносятся диапазоны значений типов 'short' и 'int'. Если вдруг окажется, что на данной платформе диапазон 'short' совпадает с диапазоном 'int', то 'SHRT_MAX' будет совпадать с 'INT_MAX', и результатом этого будет точно такое же неопределенное поведение, как и в случае с 'i'. Т.е. дальше гадать незачем.

Если же диапазон 'short' меньше диапазона 'int', то выражение 'SHRT_MAX + 1' будет вычислено успешно и его результат будет иметь тип 'int'. Затем полученным значением будет инициализироваться переменная 's'. Полученное значение не помещается в диапазон типа 'short', поэтому в процессе инициализации это значение будет преобразовано каким-то образом, определяемым реализацией (см. 4.7/3). (Подчеркну, что здесь нет неопределенного поведенеия, а есть поведение, определяемое реализацией.) Таким образом невозможно абстрактно сказать, какое значение получится в результате инициализации в 's'. В общем случае — любое.

Далее будет выполнена попытка инкрементировать значение 's'. '++s' эквивалентно 's = s + 1'. Если на предыдущем этапе значение 's' получилось меньше, чем 'SHRT_MAX', то оно будет просто мирно увеличено на 1. Если же в 's' было 'SHRT_MAX', то опять произойдет точно то же, что произошло на этапе инициализации (здесь му уже полагаем, что диапазон 'short' меньше диапазона 'int'), т.е. в 's' попадет какое-то значение, определяемое реализацией.

Таким образом, если рассматривать этот код как единое целое, то ответа на твой вопрос не существует потому, что этот код обязательно порождает неопределенное поведение (из-за 'INT_MAX + 1').

Если рассматривать 's' и 'i' неазависимо, то про 'i' опять говорить нечего, ибо неопределенное поведение.

А про 's' можно сказать, что все это либо приведет к неопределенному поведению, либо к печати некоего определяемого реализацией значения (т.е. в общем случае — любого).
Best regards,
Андрей Тарасевич
Re[2]: Int overflow (простой вопрос)
От: Посторонним В. Беларусь  
Дата: 16.12.06 23:12
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>Здравствуйте, Посторонним В., Вы писали:


АТ>У тебя тут слишком много свалено в кучу, чтобы понять, в чем именно состоит суть вопроса... Ну да ладно.


АТ>Сначала рассмотрим то, что связано с переменной 'i'

. ..
Спасибо огромное за такой подробный ответ!
Еще раз перечитаю завтра с утра на свежую голову. Вместо
SHRT_MAX + 1 следовало читать SHRT_MAX
и соответственно
вместо INT_MAX + 1 следовало читать INT_MAX

голова дурная уже в час ночи
но как я понял от этого ничего не поменяется: все равно будет в обоих случаях будет UB
Ну завтра все еще раз внимательно перечитаю и уточню, если что не понял.
Re[2]: Int overflow (простой вопрос)
От: Посторонним В. Беларусь  
Дата: 16.12.06 23:29
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>Здравствуйте, Посторонним В., Вы писали:


ПВ>>Пожалуйста объясните (со ссылкой на стандарт или авторитетов вроде Страуструпа) что должен напечатать след. код

ПВ>>
ПВ>>    short s = SHRT_MAX + 1;
ПВ>>    int i = INT_MAX + 1;
ПВ>>    cout << ++s << endl;
ПВ>>    cout << ++i << endl;
ПВ>>


АТ>У тебя тут слишком много свалено в кучу, чтобы понять, в чем именно состоит суть вопроса... Ну да ладно.


А почему в обоих случаях выражения будет вычисляться в рамках int?
Re[3]: Int overflow (простой вопрос)
От: Андрей Тарасевич Беларусь  
Дата: 17.12.06 00:14
Оценка: 3 (2)
Здравствуйте, Посторонним В., Вы писали:

ПВ>>>Пожалуйста объясните (со ссылкой на стандарт или авторитетов вроде Страуструпа) что должен напечатать след. код

ПВ>>>
ПВ>>>    short s = SHRT_MAX + 1;
ПВ>>>    int i = INT_MAX + 1;
ПВ>>>    cout << ++s << endl;
ПВ>>>    cout << ++i << endl;
ПВ>>>


АТ>>У тебя тут слишком много свалено в кучу, чтобы понять, в чем именно состоит суть вопроса... Ну да ладно.


ПВ>А почему в обоих случаях выражения будет вычисляться в рамках int?


Ну в данном конкретном случае это произойдет просто напросто потому, что оба операнда в обоих выражениях имеют тип 'int'. Макро 'SHORT_MAX' заменяется препроцессором на какой-то целочисенный литерал (например, '32767'), который будет иметь тип 'int'. А литерал '1' и так имеет тип 'int'.

А в общем, в С++ перед вычислением выражения выполняются так называемые usual arithmetic conversions (см. 5.5/9), которые включают в себя integral promotions (см. 4.5). Одним из результатов этого является то, что выражения никогда не вычисляются в рамках типов, "меньших" чем 'int' (или 'unsigned int'). Т.е. любые операнды типов '[signed/unsigned]char' и '[signed/unsigned] short' сначала приводятся к типу 'int' (или 'unsigned int') и только потом выполняется вычисление выражения.

Последнее значит, что даже если некая реализация захочет определить 'SHORT_MAX' как '((short) 32767)' (не помню навскидку, легально ли это), и даже если ты при этом насильно приведешь единицу к типу 'short' (т.е. получится '(short) 32767 + (short) 1'), выражение тем не менее все равно будет вычисляться в рамках типа 'int'.
Best regards,
Андрей Тарасевич
Re[3]: Int overflow (простой вопрос)
От: Андрей Тарасевич Беларусь  
Дата: 17.12.06 00:18
Оценка: 2 (1)
Здравствуйте, Посторонним В., Вы писали:

ПВ>Вместо

ПВ>SHRT_MAX + 1 следовало читать SHRT_MAX
ПВ>и соответственно
ПВ>вместо INT_MAX + 1 следовало читать INT_MAX

ПВ>голова дурная уже в час ночи

ПВ>но как я понял от этого ничего не поменяется: все равно будет в обоих случаях будет UB

Общий итог — не поменяется. Просто все те же эффекты теперь переместятся от инициализаций к инкрементам.

В случае с 'i' мы опять получим неопределенное поведение на инкременте '++i' по тем же причинам.

В случае с 's' мы опять получаем либо неопределеное поведение (если диапазон 'short' совпадает с диапазоном 'int'), либо результат, определяемый реализацией (в противном случае). По тем же причинам.

Т.е. конкретного ответа в общем случае по-прежнему нет.
Best regards,
Андрей Тарасевич
Re[4]: Int overflow (простой вопрос)
От: Посторонним В. Беларусь  
Дата: 17.12.06 10:01
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>Здравствуйте, Посторонним В., Вы писали:


АТ>>>У тебя тут слишком много свалено в кучу, чтобы понять, в чем именно состоит суть вопроса... Ну да ладно.


ПВ>>А почему в обоих случаях выражения будет вычисляться в рамках int?


АТ>А в общем, в С++ перед вычислением выражения выполняются так называемые usual arithmetic conversions (см. 5.5/9), которые включают в себя integral promotions (см. 4.5). Одним из результатов этого является то, что выражения никогда не вычисляются в рамках типов, "меньших" чем 'int' (или 'unsigned int'). Т.е. любые операнды типов '[signed/unsigned]char' и '[signed/unsigned] short' сначала приводятся к типу 'int' (или 'unsigned int') и только потом выполняется вычисление выражения.


Спасибо!
Теперь все вопросы сняты
Re[2]: Int overflow (простой вопрос)
От: saproj  
Дата: 18.12.06 14:57
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

ПВ>>
ПВ>>    ...
ПВ>>    int i = INT_MAX + 1;
ПВ>>    ...
ПВ>>


АТ>Сначала рассмотрим то, что связано с переменной 'i'. Тут все просто: в процессе инициализации 'i' производится вычисление выражения 'INT_MAX + 1'. Это выражение вычисляется в рамках типа 'int' и приводит к переполнению, т.к. значение 'INT_MAX + 1' не помещается в диапазон значений типа 'int'. Это приводит к неопределенному поведению (см. 5/5).

А обязан ли компилятор скомпилить такой код?
Re[4]: Int overflow (простой вопрос)
От: Максим2006 Беларусь  
Дата: 18.12.06 16:07
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>Здравствуйте, Посторонним В., Вы писали:


ПВ>>>>Пожалуйста объясните (со ссылкой на стандарт или авторитетов вроде Страуструпа) что должен напечатать след. код

ПВ>>>>
ПВ>>>>    short s = SHRT_MAX + 1;
ПВ>>>>    int i = INT_MAX + 1;
ПВ>>>>    cout << ++s << endl;
ПВ>>>>    cout << ++i << endl;
ПВ>>>>


АТ>>>У тебя тут слишком много свалено в кучу, чтобы понять, в чем именно состоит суть вопроса... Ну да ладно.


ПВ>>А почему в обоих случаях выражения будет вычисляться в рамках int?


АТ>Ну в данном конкретном случае это произойдет просто напросто потому, что оба операнда в обоих выражениях имеют тип 'int'. Макро 'SHORT_MAX' заменяется препроцессором на какой-то целочисенный литерал (например, '32767'), который будет иметь тип 'int'. А литерал '1' и так имеет тип 'int'.


Получается, что
unsigned int ui = INT_MAX + 1;
тоже даст UB?
Оригинально
Re[3]: Int overflow (простой вопрос)
От: wils0n www.atzone.org
Дата: 18.12.06 19:49
Оценка:
Здравствуйте, saproj, Вы писали:

S>Здравствуйте, Андрей Тарасевич, Вы писали:


ПВ>>>
ПВ>>>    ...
ПВ>>>    int i = INT_MAX + 1;
ПВ>>>    ...
ПВ>>>


S>А обязан ли компилятор скомпилить такой код?

А какие могут быть проблемы на стадии компиляции?
Складываются константа и литерал одного типа. Присваивается тому же типу.
gcc 4.2
Re[5]: Int overflow (простой вопрос)
От: wils0n www.atzone.org
Дата: 18.12.06 20:21
Оценка:
Здравствуйте, Максим2006, Вы писали:

М>Получается, что
unsigned int ui = INT_MAX + 1;
тоже даст UB?

М>Оригинально
g++ на такой код выдаёт warning: overflow in implicit constant conversion
что в принципе объяснимо. во-первых, складываются два int'a, значит результат будет int, а не unsigned int.
Во-вторых, результат будет заведомо отрицательным, а мы хотим unsigned int.
gcc 4.2
Re[3]: Int overflow (простой вопрос)
От: elcste  
Дата: 19.12.06 02:16
Оценка:
Здравствуйте, saproj, Вы писали:

ПВ>>>    int i = INT_MAX + 1;

S>А обязан ли компилятор скомпилить такой код?

Нет, не обязан.

Note: permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).

Re[4]: Int overflow (простой вопрос)
От: sevanew  
Дата: 19.12.06 07:29
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>Здравствуйте, Посторонним В., Вы писали:


ПВ>>Вместо

ПВ>>SHRT_MAX + 1 следовало читать SHRT_MAX
ПВ>>и соответственно
ПВ>>вместо INT_MAX + 1 следовало читать INT_MAX

ПВ>>голова дурная уже в час ночи

ПВ>>но как я понял от этого ничего не поменяется: все равно будет в обоих случаях будет UB

АТ>Общий итог — не поменяется. Просто все те же эффекты теперь переместятся от инициализаций к инкрементам.


АТ>В случае с 'i' мы опять получим неопределенное поведение на инкременте '++i' по тем же причинам.


АТ>В случае с 's' мы опять получаем либо неопределеное поведение (если диапазон 'short' совпадает с диапазоном 'int'), либо результат, определяемый реализацией (в противном случае). По тем же причинам.


АТ>Т.е. конкретного ответа в общем случае по-прежнему нет.



почему нет конкретного ответа, я посмотрел на код ассемблера и пришел у видел то, что и ожидалось. Вот ассм прпрограмма написанная мной в спреде VC++6, поставив точки останова можно посмотреть значение регистров и переменных, ответ будет 0x80000000:
main()
{
int A;
bool wasOverflow = FALSE; // переменная, в которую бедет запизано TRUE в случае переполнения
A = INT_MAX + 1; // кладем максимальное чило, если добавим +1 то будет переполнение,
__asm{
push eax;
mov eax, A;

ADD eax, 1; // +1
jnc exit_assm
mov wasOverflow, TRUE
exit_assm:
pop eax;

}
}
Re[6]: Int overflow (простой вопрос)
От: Максим2006 Беларусь  
Дата: 19.12.06 07:55
Оценка:
Здравствуйте, wils0n, Вы писали:

W>Здравствуйте, Максим2006, Вы писали:


М>>Получается, что
unsigned int ui = INT_MAX + 1;
тоже даст UB?

М>>Оригинально

W>g++ на такой код выдаёт warning: overflow in implicit constant conversion

VC тоже

W>что в принципе объяснимо. во-первых, складываются два int'a, значит результат будет int, а не unsigned int.

W>Во-вторых, результат будет заведомо отрицательным, а мы хотим unsigned int.
Он будет не отрицательным, а вообще не определённым (UB)
А вообще, преобразование из int в unsigned вполне законно.

Просто грустно от того, что компилятор не отлавливает тип результата константного выражения. Хотя мог бы
Re[5]: Int overflow (простой вопрос)
От: Андрей Тарасевич Беларусь  
Дата: 20.12.06 02:31
Оценка:
Здравствуйте, sevanew, Вы писали:

ПВ>>>Вместо

ПВ>>>SHRT_MAX + 1 следовало читать SHRT_MAX
ПВ>>>и соответственно
ПВ>>>вместо INT_MAX + 1 следовало читать INT_MAX

ПВ>>>голова дурная уже в час ночи

ПВ>>>но как я понял от этого ничего не поменяется: все равно будет в обоих случаях будет UB

АТ>>Общий итог — не поменяется. Просто все те же эффекты теперь переместятся от инициализаций к инкрементам.


АТ>>В случае с 'i' мы опять получим неопределенное поведение на инкременте '++i' по тем же причинам.


АТ>>В случае с 's' мы опять получаем либо неопределеное поведение (если диапазон 'short' совпадает с диапазоном 'int'), либо результат, определяемый реализацией (в противном случае). По тем же причинам.


АТ>>Т.е. конкретного ответа в общем случае по-прежнему нет.


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


В языке С++ нет никакого "кода ассемблера" и смотреть, сответственно, некуда. Ты увидел "то, что и ожидалось" в коде, сгенерированном конкретным компилятором. Я же вел речь об общем случае.
Best regards,
Андрей Тарасевич
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.