Как использовать тип 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 шт):

Автор решения: iEPCBM

В scanf_s (да и просто в scanf) код "%d" требует 4-байтную переменную. Тип char занимает 1 байт. Здесь лучше применять тип int (4 байта).

Однако вы можете преобразовать тип char* в тип int*:

scanf_s("%d", (int*)(&f), 4);

, но вы тогда должны гарантировать, что введенное число занимает не более 1 байта.

→ Ссылка
Автор решения: nick_n_a

По вопросам 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 - поэтому... так себе идея с массивом, я обычно использую массив там где гарантировано нужно сэкономить память. В плане быстродействия это выигрыш недаст, выигрыш такая упаковка даст - если у вас глубокая рекурсия, или если вы работаете с большими массивами данных - тогда можно заморочится с размером, если надо добится меньшего расхода памяти. Меньший расход памяти при больших обьёмах - позволяет увеличить быстродействие в отдельных случаях. Для конкретно вашего случая всем этим можно принебречь.

→ Ссылка