Выражение C оценивается по-разному на двух разных компиляторах

У меня есть код, который работает по-разному между GCC и Atmel Studio:

uint32_t tc = 107900;
int8_t   m  = 59;

tc = tc - (m*1800);

В GCC результат в tc равен 1700, как и предполагалось.

В AtmelStudio результат в tc равен 132772, что неверно.

Проблема, по-видимому, заключается в том, что член m*1800 вычисляется с ограниченной точностью m с помощью AtmelStudio.

Мой вопрос в том, какой компилятор делает это правильно?

Спасибо.


person NXT    schedule 16.04.2014    source источник
comment
Я бы предположил, что приведение m к uint32_t в выражении (т.е. tc = tc - ((uint32_t)m * 1800)) даст желаемые результаты, но я не уверен, что это требуется спецификациями языка C.   -  person Jonathon Reinhart    schedule 16.04.2014
comment
... или используйте (m*1800L), так как арифметическое произведение 59*1800 не вписывается в минимум указанный C int диапазон от -32767 до +32767, но вписывается в минимум C указан long диапазон.   -  person chux - Reinstate Monica    schedule 16.04.2014
comment
Очевидно, этот компилятор по умолчанию использует 16-битные целые числа. Ожидаемое поведение.   -  person david.pfx    schedule 19.04.2014


Ответы (2)


Оба делают это правильно. Выражение m * 1800 будет вычисляться как тип int. Если int составляет 32 бита, то это будет 106200. Если int составляет 16 бит, что является вполне приемлемым способом реализации компилятора C, то это -24872.

person Lee Daniel Crocker    schedule 16.04.2014
comment
На самом деле это не определено в последнем случае. - person R.. GitHub STOP HELPING ICE; 16.04.2014
comment
Не идеально, только стандартно, но для +1 достаточно :-) - person peterh; 16.04.2014
comment
Спасибо, так что это связано с размером типа константы по умолчанию. - person NXT; 17.04.2014
comment
@NXT: Не совсем так. Это связано с размером int по умолчанию, который здесь будет переопределен длинной константой. - person david.pfx; 19.04.2014

Кажется, что в AtmelStudio int является 16-битным, поэтому m*1800 переполняется, вызывая неопределенное поведение. В вашем случае поведение, которое дал компилятор, вероятно, было сокращением по модулю 65536 в диапазоне [-32768,32767], что дало -24872. Тогда tc - (m*1800) равно 132772.

Чтобы избежать этого, вам нужно привести m или 1800 к uint32_t или другому типу (например, long), где результат не будет переполняться до выполнения умножения.

person R.. GitHub STOP HELPING ICE    schedule 16.04.2014