Почему в приведенном ниже фрагменте кода мы получаем результат 600? Два вопроса помогут мне понять поведение.
Я надеялся получить ответ 88, который является результатом зацикливания за пределами диапазона uint8_t.
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
void main()
{
uint8_t b = 200;
printf("%" PRIu8 "\n",b+b+b);
printf("%" PRIu8 "\n",3*b);
}
gcc версии 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.1)
Это связано с продвижением аргументов по умолчанию.
Как упоминалось другими, существуют неявные преобразования (например,) ваш b
будет преобразован в int
или unsigned int
. Вы можете получить ожидаемый результат с помощью: `printf("%u\n",(uint8_t) (b+b+b));
@Bob__ Я искал «целочисленное продвижение по умолчанию printf», но не смог найти для этого подходящего дубликата.
@ niil87 MS Visual Studio выводит 88.
@Barmar Ну, есть это, которое близко.
@Bob__ Это один из тех, что я видел. Я не думал, что подписанный/неподписанный был достаточно близок к 8-битному/32-битному.
Кстати, так и должно быть int main(void)
.
@Bob__ Спасибо за отзыв... не знал, что это важно! stackoverflow.com/questions/8844915/…
Если мы посмотрим на inttypes.h, то обнаружим следующее:
# define PRIu8 "u"
Таким образом, этот спецификатор формата не содержит модификатора длины. Это имеет смысл в контексте соответствующего аргумента, поскольку невозможно передать uint8_t
функции с переменным числом аргументов. Поскольку этот тип имеет меньший ранг, чем int
, значение этого типа будет повышено до int
. Это продвижение также происходит в выражениях b+b+b
и 3*b
.
Если вы явно используете модификатор длины для char
, вы получите ожидаемый результат.
printf("%hhd\n",b+b+b);
printf("%hhd\n",3*b);
Похоже на ошибку в библиотеке
@VladfromMoscow Для меня это тоже. Я ожидаю, что он будет напечатан правильно.
На мой взгляд, это ошибка библиотеки.
В MS Visual Studio макрос PRIu8
расширяется до hhu
как и должно быть и вы получаете ожидаемый результат.
Интересно отметить, что если использовать clang, то если вы напишете, например,
printf("%" PRIu8 "\n",( uint8_t)(b+b+b));
когда снова вы получите ожидаемый результат.
В C всякий раз, когда вы вызываете функцию с аргументами с многоточием (...
), например printf, все эти аргументы будут продвигаться по умолчанию. Это означает, что любой меньший целочисленный тип будет преобразован в int
и передан таким образом. Таким образом, в printf префиксы типов h
не имеют значения - они будут игнорироваться printf и не будут иметь никакого эффекта (поскольку аргумент в любом случае должен быть int
).
Кроме того, такое же преобразование меньших целых типов будет происходить для любого арифметического оператора (например, +
или *
), и результирующая операция будет выполняться с int
точностью, давая int
результат.
Чтобы получить ожидаемый результат, явно замаскируйте его до соответствующего размера:
printf("%u\n", (b+b+b) & 0xff);
Спасибо за ваш ответ, что такое префиксы типа h?
Где-то наверняка есть обман, но, пожалуйста, прочитайте о неявных преобразованиях , в частности о целочисленном продвижении и обычных арифметических преобразованиях. Если вы хотите, чтобы результат был
uint8_t
, вам нужен слепок: godbolt.org/z/rjxejqrEb