Здравствуйте, Посторонним В., Вы писали:
ПВ>Пожалуйста объясните (со ссылкой на стандарт или авторитетов вроде Страуструпа) что должен напечатать след. код ПВ>
ПВ> 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' можно сказать, что все это либо приведет к неопределенному поведению, либо к печати некоего определяемого реализацией значения (т.е. в общем случае — любого).
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Здравствуйте, Посторонним В., Вы писали:
АТ>У тебя тут слишком много свалено в кучу, чтобы понять, в чем именно состоит суть вопроса... Ну да ладно.
АТ>Сначала рассмотрим то, что связано с переменной 'i'
. ..
Спасибо огромное за такой подробный ответ!
Еще раз перечитаю завтра с утра на свежую голову. Вместо
SHRT_MAX + 1 следовало читать SHRT_MAX
и соответственно
вместо INT_MAX + 1 следовало читать INT_MAX
голова дурная уже в час ночи
но как я понял от этого ничего не поменяется: все равно будет в обоих случаях будет UB
Ну завтра все еще раз внимательно перечитаю и уточню, если что не понял.
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Здравствуйте, Посторонним В., Вы писали:
ПВ>>Пожалуйста объясните (со ссылкой на стандарт или авторитетов вроде Страуструпа) что должен напечатать след. код ПВ>>
ПВ>> short s = SHRT_MAX + 1;
ПВ>> int i = INT_MAX + 1;
ПВ>> cout << ++s << endl;
ПВ>> cout << ++i << endl;
ПВ>>
АТ>У тебя тут слишком много свалено в кучу, чтобы понять, в чем именно состоит суть вопроса... Ну да ладно.
А почему в обоих случаях выражения будет вычисляться в рамках int?
Здравствуйте, Посторонним В., Вы писали:
ПВ>>>Пожалуйста объясните (со ссылкой на стандарт или авторитетов вроде Страуструпа) что должен напечатать след. код ПВ>>>
ПВ>>> 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'.
Здравствуйте, Посторонним В., Вы писали:
ПВ>Вместо ПВ>SHRT_MAX + 1 следовало читать SHRT_MAX ПВ>и соответственно ПВ>вместо INT_MAX + 1 следовало читать INT_MAX
ПВ>голова дурная уже в час ночи ПВ>но как я понял от этого ничего не поменяется: все равно будет в обоих случаях будет UB
Общий итог — не поменяется. Просто все те же эффекты теперь переместятся от инициализаций к инкрементам.
В случае с 'i' мы опять получим неопределенное поведение на инкременте '++i' по тем же причинам.
В случае с 's' мы опять получаем либо неопределеное поведение (если диапазон 'short' совпадает с диапазоном 'int'), либо результат, определяемый реализацией (в противном случае). По тем же причинам.
Т.е. конкретного ответа в общем случае по-прежнему нет.
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Здравствуйте, Посторонним В., Вы писали:
АТ>>>У тебя тут слишком много свалено в кучу, чтобы понять, в чем именно состоит суть вопроса... Ну да ладно.
ПВ>>А почему в обоих случаях выражения будет вычисляться в рамках int?
АТ>А в общем, в С++ перед вычислением выражения выполняются так называемые usual arithmetic conversions (см. 5.5/9), которые включают в себя integral promotions (см. 4.5). Одним из результатов этого является то, что выражения никогда не вычисляются в рамках типов, "меньших" чем 'int' (или 'unsigned int'). Т.е. любые операнды типов '[signed/unsigned]char' и '[signed/unsigned] short' сначала приводятся к типу 'int' (или 'unsigned int') и только потом выполняется вычисление выражения.
АТ>Сначала рассмотрим то, что связано с переменной 'i'. Тут все просто: в процессе инициализации 'i' производится вычисление выражения 'INT_MAX + 1'. Это выражение вычисляется в рамках типа 'int' и приводит к переполнению, т.к. значение 'INT_MAX + 1' не помещается в диапазон значений типа 'int'. Это приводит к неопределенному поведению (см. 5/5).
А обязан ли компилятор скомпилить такой код?
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Здравствуйте, Посторонним В., Вы писали:
ПВ>>>>Пожалуйста объясните (со ссылкой на стандарт или авторитетов вроде Страуструпа) что должен напечатать след. код ПВ>>>>
ПВ>>>> short s = SHRT_MAX + 1;
ПВ>>>> int i = INT_MAX + 1;
ПВ>>>> cout << ++s << endl;
ПВ>>>> cout << ++i << endl;
ПВ>>>>
АТ>>>У тебя тут слишком много свалено в кучу, чтобы понять, в чем именно состоит суть вопроса... Ну да ладно.
ПВ>>А почему в обоих случаях выражения будет вычисляться в рамках int?
АТ>Ну в данном конкретном случае это произойдет просто напросто потому, что оба операнда в обоих выражениях имеют тип 'int'. Макро 'SHORT_MAX' заменяется препроцессором на какой-то целочисенный литерал (например, '32767'), который будет иметь тип 'int'. А литерал '1' и так имеет тип 'int'.
Здравствуйте, saproj, Вы писали:
S>Здравствуйте, Андрей Тарасевич, Вы писали:
ПВ>>>
ПВ>>> ...
ПВ>>> int i = INT_MAX + 1;
ПВ>>> ...
ПВ>>>
S>А обязан ли компилятор скомпилить такой код?
А какие могут быть проблемы на стадии компиляции?
Складываются константа и литерал одного типа. Присваивается тому же типу.
Здравствуйте, Максим2006, Вы писали:
М>Получается, что
unsigned int ui = INT_MAX + 1;
тоже даст UB? М>Оригинально
g++ на такой код выдаёт warning: overflow in implicit constant conversion
что в принципе объяснимо. во-первых, складываются два int'a, значит результат будет int, а не unsigned int.
Во-вторых, результат будет заведомо отрицательным, а мы хотим unsigned int.
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).
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Здравствуйте, Посторонним В., Вы писали:
ПВ>>Вместо ПВ>>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;
Здравствуйте, 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 вполне законно.
Просто грустно от того, что компилятор не отлавливает тип результата константного выражения. Хотя мог бы
Здравствуйте, sevanew, Вы писали:
ПВ>>>Вместо ПВ>>>SHRT_MAX + 1 следовало читать SHRT_MAX ПВ>>>и соответственно ПВ>>>вместо INT_MAX + 1 следовало читать INT_MAX
ПВ>>>голова дурная уже в час ночи ПВ>>>но как я понял от этого ничего не поменяется: все равно будет в обоих случаях будет UB
АТ>>Общий итог — не поменяется. Просто все те же эффекты теперь переместятся от инициализаций к инкрементам.
АТ>>В случае с 'i' мы опять получим неопределенное поведение на инкременте '++i' по тем же причинам.
АТ>>В случае с 's' мы опять получаем либо неопределеное поведение (если диапазон 'short' совпадает с диапазоном 'int'), либо результат, определяемый реализацией (в противном случае). По тем же причинам.
АТ>>Т.е. конкретного ответа в общем случае по-прежнему нет.
S>почему нет конкретного ответа, я посмотрел на код ассемблера и пришел у видел то, что и ожидалось....
В языке С++ нет никакого "кода ассемблера" и смотреть, сответственно, некуда. Ты увидел "то, что и ожидалось" в коде, сгенерированном конкретным компилятором. Я же вел речь об общем случае.