- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
#include <iostream>
#include <string>
using namespace std;
struct A
{
uint16_t n;
uint8_t a1:1;
uint8_t a2:1;
uint8_t a3:1;
uint8_t a4:1;
uint8_t a5:4;
uint8_t b;
} __attribute__((packed));
int main()
{
char v[] = { 0x1, 0x1, 0b01010011, 0x9 };
A *p = (A*)v;
cout << (uint16_t)p->a1 << endl;
cout << (uint16_t)p->a2 << endl;
cout << (uint16_t)p->a3 << endl;
cout << (uint16_t)p->a4 << endl;
cout << (uint16_t)p->a5 << endl;
cout << (uint16_t)p->b << endl;
}
Хотя, половина бита - это нечто невозможное.
К сожалению, пролетающий воздушный шар Пётр Иванович не заметил. С неохотой оторвавшись от окна он оделся, проверил плиту, взял ключи и вышел за дверь. Проезжающий по мокрому асфальту серебряный «Hyundai Solaris» не справился с управлением и не успел затормозить. Петра Ивановича не стало.
Вот это и есть примерно половина бита.
От половины бита и сишник взвоет. Хотя и такое бывает, конечно.
Вот у нас есть «половина бита» b1 (в памяти она занимает целый бит — будем считать это выравниванием) и «половинка бита» b2, а в программе везде используется только (b1 xor b2) или (b1 == b2). Тогда, зная только b1 или только b2, мы не сможем предугадать поведение программы, а зная значения обоих, будем знать результат.
при bitwise-операциях может стать отсутствием одного бита
Упихал два значения — 1 и 0 — в один бит, проверь.
Хз зачем я это сделал
Ну вот и на сишке так сделай и всё будет норм. Только сдвиг ещё добавить надо, если значение А5 интересно.
Чисто чтобы потом людям удобнее читать было, если нужно станет, видимо.
Я уж не совсем новичок, лет 6-7 уже опыт на крестах.
Ну если их не сериализовывать (или сериализовывать только в рамках одного приложения на одной машине) — действительно лучше же.
Если тебе пофиг на их внутреннее представление - да, они довольно удобны.
Но тебе же не пофиг, раз ты полез байты разглядывать. Видимо пытаешься совместимость с чем-то запинать. В этом случае я бы не стал юзать битовые поля.
Хотя подогнать порядок можно, конечно. И в пределах одного ABI он не уплывёт. Конпеляторы, соблюдающие одно ABI, всё-таки стараются чтобы сишные интерфейсы между ними не ломались.
1
1
0
0
5
9
Видимо багрепорт придется писать.
Allocation of bit-fields within a class object is implementation-defined. Alignment of bit-fields is implementation-defined.
Удачного багрепорта.
З.Ы. Именно поэтому я никогда не юзаю битфилды.
при этом чтобы на высоком уровне оставался доступ через foo.a = 100;
Значит он будет в конце байта.
Ну и x86 всё-таки little-endian, младшим байтом вперёд.
Порядок битов - это скорее о каком-нибудь последовательном порту, в который мы биты один за другим срём. А с точки зрения проца порядка битов обычно и нет. Он их все одновременно выгружает.
• Одни компиляторы пушат в стек переменные по очереди, так что последняя переменная находится ниже всех.
• Другие компиляторы сразу выделяют память в стеке (sub rsp, константа) и размещают переменные в порядке их объявления, так что последняя переменная оказывается выше всех.
И вроде оба способа имеют право на существование, потому что из хорошего кода есть доступ только к переменным по отдельности, по их имени, а доступа к локальным переменным как к массиву нет.
Значит, и тут в хорошем коде должен быть доступ только к битовым полям по отдельности, по их имени, чтобы не думать о порядке упаковки?
Значит, для сериализации нужно собирать байты ручками?
Проверил несколько реализаций «Паскаля» — дискриминант (поле, указывающее на то, какой из вариантов активен) проверяет только «Irie Pascal» (который сейчас никому не нужен, потому что он поддерживает только «Standard Pascal» без расширений).
Приведите реальные примеры инструкций x86, у которых есть доступ к битам по номеру.
Где здесь хуйня, YpaHeLI_?
Берём 0b01010011, наименее значащий бит — первое битовое поле, следующий за наименее значащим — второе, потом третье, и так далее, и тому подобное. a5 получается простым сдвигом вправо на 4 бита.
ну это, походу, вот такой вариант
4 ноды по 2 цпу (= 8 цпу) и 24 слота памяти на ноду (=96 слотов)
если заебенить 256ГБ модули, как раз 24ТБ и выйдет
а зионы 28 ядерные (8*28*2), чтобы получить 448 vcpu
Выходит, DRAM контроллер управляет не чипами, а управляет он буфером, который эмулирует для него этакий виртуальный "ранк".
Получается, что контроллер может поддержать куда больше памяти, но наверныяка за счет некоторой латентности буфера.
Впрочем, там наверное такие кеши, что это и не важно.