scanf ("% d", char *) - строка формата char-as-int? - PullRequest
2 голосов
/ 14 июня 2010

Что такое модификатор строки формата для char-as-number?

Я хочу прочитать число, никогда не превышающее 255 (на самом деле намного меньше), в переменную типа unsigned char, используя sscanf.1004 * Используя типичные

 char source[] = "x32";
 char separator;
 unsigned char dest;
 int len;

 len = sscanf(source,"%c%d",&separator,&dest);
 // validate and proceed...

Я получаю ожидаемое предупреждение: аргумент 4 в sscanf имеет тип char *, int * Ожидается.

Как я понимаю, спецификации нетмодификатор char (например,% sd для коротких или% lld для 64-битных длин)

  • это опасно?(переполнит только переполнит (перевернет) переменную или будет записывать вне выделенного пространства?)
  • Есть ли более красивый способ добиться этого, чем выделение временной переменной int?
  • .... или вы бы предложили совершенно иной подход?

Ответы [ 6 ]

4 голосов
/ 14 июня 2010

Вы можете использовать %hhd в glibc scanf(), MSVC не поддерживает целочисленное хранение в символ непосредственно (см. MSDN Спецификация ширины scanf для получения дополнительной информации о поддерживаемые преобразования)

1 голос
/ 14 июня 2010

Использовать это опасно.Поскольку существует неявное приведение из unsigned char * к int *, если число больше 0xFF, оно будет использовать байты (макс. 3) рядом с переменной в стеке и искажать их значения.

Проблема с% hhd заключается в том, что в зависимости от размера целого (не обязательно 4 байта) он может быть не 1 байтом.

Кажется, что sscanf не поддерживает хранение чисел в символ, я предлагаю вамвместо этого используйте int.Хотя, если вы хотите перебросить символ, вы можете просто затем бросить int в тип char, например:

int dest;
int len;

len = sscanf(source,"%c%d",&separator,&dest);
dest = (unsigned char)dest;
0 голосов
/ 14 июня 2010

Это опасно.Scanf запишет целочисленное значение над символьной переменной.В вашем примере (скорее всего) ничего не произойдет, если вы не реорганизуете свои переменные стека (scanf будет частично перезаписывать len при попытке записать целочисленный размер «dest», но затем он возвращает правильное «len» и перезаписывает его «правильным» значением).

Вместо этого делайте «правильные вещи», а не полагайтесь на настроение компилятора:

 char source[] = "x32";
 char separator;
 unsigned char dest;
 int temp;
 int len;

 len = sscanf(source,"%c%d",&separator,&temp);
 // validate and proceed...

 if (temp>=YOUR_MIN_VALUE && temp<=YOUR_MAX_VALUE) {
   dest = (unsigned char)temp;
 } else {
   // validation failed
 }
0 голосов
/ 14 июня 2010

Вероятно, самым простым способом было бы загрузить число просто во временное целое число и сохранить его, только если оно находится в требуемых границах.(и вам, вероятно, понадобится что-то вроде unsigned char result = tempInt & 0xFF;)

0 голосов
/ 14 июня 2010

Это невозможно сделать.

sscanf никогда не будет записывать один байт при чтении целого числа.

Если вы передадите указатель на один выделенный байт в качестве указателя на int, у вас закончатся границы. Это может быть хорошо из-за выравнивания по умолчанию, но вы не должны полагаться на это.

Создать временный. Таким образом, вы также сможете проверить его во время выполнения.

0 голосов
/ 14 июня 2010

Я не хочу читать число никогда превышающий 255 (на самом деле намного меньше) в переменную типа unsigned char используя sscanf.

В большинстве случаев вы экономите мало на что, используя char для целого числа.

Как правило, это зависит от архитектуры и компилятора, но большинство современных процессоров не очень хорошо обрабатывают типы данных, которые отличаются по размеру от регистра. (Заметным исключением является 32-битный тип int для 64-битных архитектур.)

Добавление здесь штрафов за доступ к памяти без согласования со словами ЦП (не спрашивайте меня, зачем это делают ЦП), использование char должно быть ограничено случаями, когда действительно нужен символ или потребление памяти является проблемой.

...