Проблема с выбором байтов из целочисленной переменной

Я пытаюсь выдавить 4 значения символов из одного целого числа. Во всех моих попытках я получаю одинаковые результаты. Младшие байты старшего и младшего слова читаются правильно, но старшие байты расширяются до целых, а добавленные байты заполняются единицами. Где я делаю ошибку?

Вот пример кода моих попыток. Я компилировал его с помощью GCC:

#include <stdio.h>

#define PRINT   printf("b1 %u\n", bb1);\
            printf("b2 %u\n", bb2);\
            printf("b3 %u\n", bb3);\
            printf("b4 %u\n", bb4)

typedef union{
    int integer;
    struct{
        char b1;
        char b2;
        char b3;
        char b4;
    };
}bytes;

typedef struct{
    char b1:8;
    char b2:8;
    char b3:8;
    char b4:8;
}bitfield;


int main()
{
    int a;
    printf("int size = %u\n", a=sizeof(int));
    printf("char size = %u\n", a=sizeof(char));
    bytes in_union;
    bitfield in_struct;
    // values stored in bytes 
    // hword.hi 240 hword.lo 15
    // lword.hi 129 lword.lo 126
    int value = 4027548030;
    
    // #1 solution with union
    in_union.integer = value;
    
    char bb1 = in_union.b1;
    char bb2 = in_union.b2;
    char bb3 = in_union.b3;
    char bb4 = in_union.b4;
    PRINT;
    
    // #2 with pointer to union
    char* uptr;
    uptr = (char*)&in_union;
    bb1 = *uptr;
    bb2 = *(uptr+1);
    bb3 = *(uptr+2);
    bb4 = *(uptr+3);
    PRINT;
    
    // #3 with void pointer to union
    void* vptr;
    vptr = &in_union;
    bb1 = *(char*)vptr;
    bb2 = *(char*)(vptr+1);
    bb3 = *(char*)(vptr+2);
    bb4 = *(char*)(vptr+3);
    PRINT;
    
    // #4 with pointer to value variable
    char* ptr = (char*)&value;
    bb1 = *ptr;
    bb2 = *(ptr+1);
    bb3 = *(ptr+2);
    bb4 = *(ptr+3);
    PRINT;
    
    // #5 with bitfield
    in_struct.b1 = (char)value;
    in_struct.b2 = (char)(value>>8);
    in_struct.b3 = (char)(value>>16);
    in_struct.b4 = (char)(value>>24);
    bb1 = in_struct.b1;
    bb2 = in_struct.b2;
    bb3 = in_struct.b3;
    bb4 = in_struct.b4;
    PRINT;
    
return 0;
}

Все дает одинаковые результаты:

bb1 = 126
bb2 = 4294967169
bb3 = 15
bb4 = 4294967280

Ожидаемые значения:

bb1 = 126
bb2 = 127
bb3 = 15
bb4 = 240

Прежде чем ожидать слишком многого от своей программы, включите дополнительные параметры предупреждений при компиляции и исправьте их все. пример

Ted Lyngmo 25.08.2024 22:54

Вам нужно использовать unsigned char.

Weather Vane 25.08.2024 23:26

Кроме того: это // #3 with void pointer to union не будет компилироваться в MSVC: ошибка C2036: 'void *': неизвестный размер показывает, что вы не можете использовать арифметику указателей с указателем void* без нестандартного компилятора.

Weather Vane 25.08.2024 23:31

Хотя большинство процессоров, которые вы будете использовать, имеют прямой порядок байтов в стиле Intel, некоторые имеют обратный порядок байтов. Это означает, что при использовании такого unionb1 может быть младшим байтом или старшим байтом. Более портативно маскировать и сдвигать (например, i >> 8 & 0xff, чтобы получить второй младший байт).

John Bayko 26.08.2024 00:54
int value = 4027548030; изначально не имеет никакого смысла. Используйте тип, соответствующий присвоенному ему значению. Это приводит к принудительному преобразованию, определяемому реализацией, из некоторого большого знакового типа (long/long long) в int. Программа не гарантированно справится с этим корректно, но может выдать исключение сигнала.
Lundin 26.08.2024 10:06
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
71
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Две проблемы в вашем коде:

Первый:

Вы используете тип char для представления 4 байтов int в объявлении объединения bytes. Каждый бит 8 может представлять значение, которое может превышать максимальное значение, которое тип char может хранить в вашей системе.
Из стандарта C № 5.2.4.2.1p2 [выделено автором]

2 Если значение объекта типа char при использовании в выражении рассматривается как целое число со знаком, значение CHAR_MIN должно быть таким же, как и значение SCHAR_MIN, а значение CHAR_MAX должно быть таким же, как и значение SCHAR_MAX. В противном случае значение CHAR_MIN должно быть равно 0, а значение CHAR_MAX должно быть таким же, как и значение UCHAR_MAX.20) Значение UCHAR_MAX должно быть равно 2CHAR_BIT - 1.

Вместо типа unsigned char лучше использовать char.

Второй:

В макросе PRINT передается неверный спецификатор формата %u в print() для печати char type.
В вашем коде происходит то, что bb1, bb2, bb3 и bb4 повышаются до int, а передаваемый вами спецификатор формата — %u. Это неопределенное поведение.
Из стандарта C № 7.21.6.1p9 [выделено автором]

9 Если спецификация преобразования недействительна, поведение не определено. 282) Если какой-либо аргумент не является правильным типом для соответствующей спецификации преобразования, поведение не определено.

Измените тип bb1, bb2, bb3 и bb4 на unsigned char и используйте спецификатор формата %hhu для их печати.

С этими изменениями для ввода int value = 4027548030; получим следующий результат:

b1: 126
b2: 129
b3: 15
b4: 240

Обратите внимание, что в вашем коде есть еще несколько проблем, но я указал на основные.

Ваше предполагаемое улучшение printf("int size = %u\n", a=sizeof(int)); плохое. Вместо того, чтобы рекомендовать %d, следует printf("int size = %zu\n", sizeof(int));

Weather Vane 25.08.2024 23:35

@WeatherVane Я предлагаю макро PRINT. В коде ОП есть множество проблем, я только что указал на основные проблемы.

H.S. 25.08.2024 23:37

Ну, я не понимаю, почему ваше решение выводит отрицательные числа. В сообщении Staging Ground ОП заявил, что unsigned char решил проблему, о которой вы не упомянули.

Weather Vane 25.08.2024 23:40

@WeatherVane Обратите внимание, что в моем примере вывода я использовал значение 2027548030.

H.S. 25.08.2024 23:43

Я видел это изменение. Ценность ОП 4027548030 была бы лучше. Их ожидаемый результат имеет неотрицательные значения, а не значения байтов со знаком, которые вы показываете,

Weather Vane 25.08.2024 23:43

@WeatherVane Сформулировал и внес исправления в пост.

H.S. 26.08.2024 00:43

UV для исправления ошибочного bb2 ожидаемого значения OP.

Weather Vane 26.08.2024 00:50

Другие вопросы по теме