Как использовать тип char с целыми числами
Насколько я понимаю, тип char - символьный тип, в него можно записать один символ, например, "f". Но оказывается, его можно использовать как целочисленный тип, т.е. записать в него, например, 5 и производить какие-то операции с числами. Но я использую Visual Studio и у меня уже возникали проблемы с использованием scanf_s("%c", &ch, 1), с тем, что я не указывал размер char через запятую, в этот раз я тоже пытался использовать тип char, но на этот раз по спецификатору %d, я думаю, что в этом ошибка, потому что это единственное, что я раньше не делал, но точно я не знаю, может ещё где-то туплю. Но суть в том, что программа запускается и завершается с ненулевым кодом, и по-моему даже выдаёт неправильный ответ, для понимания я приведу полный текст программы.
Суть программы и побитовые операции не так важны, важно то, что Visual на строчках со scanf_s() выдаёт предупреждение "Предупреждение C6328 Несоответствие размера: "char" передан в качестве параметра Param(2), хотя при вызове "scanf_s" требуется "32 bit operand". Это указывает на возможную серьезную ошибку. Получение этого сообщения для функций, аналогичных scanf, может приводить к опустошению или переполнению буфера." Вроде понимаю, о чём предупреждает, но не понимаю, как это исправить. Заранее спасибо за подробное разъяснение моей проблемы. Если у Вас есть ещё какие-то комментарии по моему коду, буду благодарен их услышать. Я только учусь и рад любым замечаниям.
#include <iostream>
#include <stdio.h>
#include <Windows.h>
int main()
{
SetConsoleCP(1251);
SetConsoleOutputCP(1251);
char c;
char f;
char b;
unsigned char n;
unsigned int Word;
printf("Введите код состояния (0 - 31) > ");
scanf_s("%d", &c);
printf("Введите признак ошибки (0/1) > ");
scanf_s("%d", &f);
printf("Введите признак занятости (0/1) > ");
scanf_s("%d", &b);
printf("Введите кол-во байт (0 - 255) > ");
scanf_s("%d", &n);
Word = ((unsigned char)c & 0x1F) << 11;
Word = ((unsigned char)f & 1) << 9;
Word = ((unsigned char)b & 1) << 8;
Word = (n & 0xFF);
printf("\nВывод состояния устройства = %04x\n", Word);
return 0;
}
Ответы (2 шт):
В scanf_s (да и просто в scanf) код "%d" требует 4-байтную переменную. Тип char занимает 1 байт.
Здесь лучше применять тип int (4 байта).
Однако вы можете преобразовать тип char* в тип int*:
scanf_s("%d", (int*)(&f), 4);
, но вы тогда должны гарантировать, что введенное число занимает не более 1 байта.
По вопросам printf scanf лучше открыть msdn и почитать. Там есть ссылка на форматы, открываем её. Я искал через printf, т.к. она лучше документирована.
Читаем внимательно Format specifications спецификацию.
Так как я сталкивался с размерностью - то я уже знаю, что надо знать префиксы. Находим абзац Size Prefixes for printf and wprintf Format-Type Specifiers.
To specify Use prefix With type specifier
char
unsigned char hh d, i, o, u, x, or X
short int
short unsigned int h d, i, o, u, x, or X
...
Wide character l (lowercase L) or w c or C
Single-byte character string h s, S, or Z
Wide-character string l (lowercase L) or w s, S, or Z
Для типа число, существует префикс hh, который можно применить с i (знаковое число) или u (беззнаковое число).
Итого ответ
scanf_s("%hhd", &c);
По поводу префикса hc - hc - нужно использовать если wprintfW или wscanfW нужно заставить работать с char 8-битным вместо wchar_t 16-битным как с симолом. Для числа-байта - всёрано надо использовать hhd, или так же допустимо hhi, hho, hhu (беззнаковое), hhx (hex).
Но это не всё, есть ещё особенности. Для стековых переменных - используется выравнивание, которое всёравно изменяет размер, для x86 переменная всёравно физически будет занимать 4 байта хоть и 1 байт хранит, поэтому особого смысла переходить на 8 бит - нету. Для глобальных переменных - то же самое, но в опциях можно выключить выравнивание. Для структур - можно выключить выравнивание (надо погуглить упакованые структуры в с++), но прийдётся сложнее писать. Проще всего - создать массив char data[4]; в этом массиве - будет явно задействована вся память. Но у вас одно из чисел - unsigned - поэтому... так себе идея с массивом, я обычно использую массив там где гарантировано нужно сэкономить память. В плане быстродействия это выигрыш недаст, выигрыш такая упаковка даст - если у вас глубокая рекурсия, или если вы работаете с большими массивами данных - тогда можно заморочится с размером, если надо добится меньшего расхода памяти. Меньший расход памяти при больших обьёмах - позволяет увеличить быстродействие в отдельных случаях. Для конкретно вашего случая всем этим можно принебречь.