Могу ли я передать символ, в котором ожидается целое число в printf?

17

Правильно ли указан следующий код?

char mychar = 200;
printf("%x", mychar);

Согласно Ссылка %x ожидает целое число (4 байта с моим компилятором) и I здесь только 1 байт. Поскольку printf использует varargs, я опасаюсь, что это работает только из-за выравнивания байтов в стеке (т. Е. Char всегда использует 4 байта при нажатии на стек).

Думаю, было бы лучше написать:

char mychar = 200;
printf("%x", static_cast<int>(mychar));

Как вы думаете, первый код в любом случае безопасен? Если нет, вы думаете, что я могу получить другой результат, если я перейду на архитектуру с бигеном?

    
задан Emiliano 11.07.2012 в 13:51
источник
  • Лично я бы просто играл в нее безопасно и писал (int) mychar; в худшем случае я потратил пять персонажей, в лучшем случае я избегал UB. Кроме того, как всегда с пыльными углами языка, я предпочитаю быть более ясным / безопасным, чтобы избежать головоломки будущих читателей моего кода. –  Matteo Italia 11.07.2012 в 13:53
  • Интересный вопрос, делает ли printf безусловным нажатием? С static_cast вы всегда на безопасной стороне –  Sebastian Hoffmann 11.07.2012 в 13:53
  • @Paranaix: это не printf как таковой, а переменные аргументы, которые продвигают некоторые типы (например, float всегда повышается до double). –  Matteo Italia 11.07.2012 в 13:55
  • @Matteo Italia Ну, я скорее подумал о преобразовании в самой функции (и, следовательно, в зависимости от реализации), чем о преобразовании в самом вызове –  Sebastian Hoffmann 11.07.2012 в 13:59

4 ответа

25

В вашем примере аргумент имеет тип int . mychar повышается до int из-за промо-акций по умолчанию .

  

(C99, 6.5.2.2p6) «Если выражение, обозначающее вызываемую функцию, имеет тип, который не содержит прототип, то для каждого аргумента выполняются целые акции, а аргументы с типом float повышаются до двух. Они называются рекламными акциями по умолчанию. "

и (внимание мое):

  

(C99, 6.5.2.2p7) " Если выражение, которое обозначает вызываемую функцию, имеет тип, который включает прототип, , аргументы неявно преобразуются, как если бы они были назначены, типам из соответствующих параметров, принимая тип каждого параметра в качестве неквалифицированной версии его объявленного типа. Обозначение многоточия в деклараторе прототипа функции приводит к тому, что преобразование типа аргумента останавливается после последнего объявленного параметра. Аргумент по умолчанию   рекламные акции выполняются по завершающим аргументам . "

Обратите внимание, что технически спецификатор преобразования x требует аргумента unsigned int , но int и unsigned int будут иметь одинаковое представление.

    
ответ дан ouah 11.07.2012 в 13:53
источник
  • Это тоже хорошо подходит для C ++? –  Naveen 11.07.2012 в 13:55
  • @Naveen: Да, C ++ 11 5.2.2 / 7 говорит более или менее то же самое. –  Mike Seymour 11.07.2012 в 13:59
  • @Naveen: Да, в значительной степени. Время от времени C ++ имели разные типы (например, bool), у которых были свои собственные правила продвижения, но в остальном это одно и то же. –  MSalters 11.07.2012 в 13:59
  • Я вижу. Однако мы используем C ++ здесь. Можете ли вы подтвердить, что стандарт C ++ говорит то же самое? –  Emiliano 11.07.2012 в 14:27
  • @happy_emi, как сказал Майк, C ++ имеет в основном одно и то же правило в C ++ 11, 5.2.2p7, а также называет их рекламными акциями по умолчанию. –  ouah 11.07.2012 в 14:29
3

Это работает только для вас, потому что ваша платформа способна интерпретировать int (которому способствует продвижение char ) в качестве unsigned , это то, что ожидает %x . Чтобы быть уверенным, что это всегда работает, вы должны использовать и соответствующий спецификатор формата, а именно %d .

Поскольку кажется, что вы хотите использовать char в качестве числового количества, было бы лучше использовать два альтернативных типа signed char или unsigned char , чтобы сделать ваше намерение понятным. char может быть подписанным или неподписанным типом на вашей платформе. Правильный спецификатор для unsigned char будет тогда %hhx .

    
ответ дан Jens Gustedt 11.07.2012 в 14:04
источник
  • Не использует ли% d только надежно работать при самом предположении, что символ подписан? –  Fred Foo 11.07.2012 в 14:09
  • C говорит, что int и unsigned int имеют одинаковый размер и одинаковое требование выравнивания в C99, 6.2.5p6. –  ouah 11.07.2012 в 14:10
  • @larsmans, он может только потерпеть неудачу на гипотетической архитектуре, где char без знака и имеет ту же ширину, что и unsigned int. На всех других архитектурах char продвигается к int, а не к unsigned int. –  Jens Gustedt 11.07.2012 в 14:13
  • @ouah, да, но unsigned int может иметь биты заполнения и ловушки. Хотя это маловероятно, и еще более маловероятно встретить такое ловушечное представление при продвижении с символа :) –  Jens Gustedt 11.07.2012 в 14:15
  • @JensGustedt: ах, я вижу. Благодаря! –  Fred Foo 11.07.2012 в 14:18
0

Просто используйте printf («% hhx», mychar) . И, пожалуйста, не используйте cplusplus.com в качестве ссылки. Этот вопрос только доказывает, что его репутация содержит много ошибок и не содержит много информации.

    
ответ дан user283145 13.07.2012 в 20:18
источник
0

Если вы используете C ++, вместо этого вы можете использовать потоки.

Вам нужно будет наложить символы на целые числа, иначе они будут напечатаны как глифы. Кроме того, подписанные символы будут отображаться во время трансляции, поэтому лучше использовать unsigned char. Например, char, содержащий 0xFF, будет печататься как 0xFFFFFFFF, если сначала не сбрасывается на unsigned char.

#include <iostream>
#include <iomanip>

int main(void){

    char c = 0xFF;
    std::cout << std::hex << std::setw(2) << std::setfill('0');
    std::cout << static_cast<int>(static_cast<unsigned char>(c)) << std::endl;

    return 0;
}
    
ответ дан tprk77 11.07.2012 в 14:20
источник
  • Off topic - есть веские причины продолжать использовать stdio в C ++. –  Alexandre C. 20.07.2012 в 00:03