Предположим, что у нас есть 64-битная машина x86, которая имеет младший порядок байтов и поэтому хранит младший байт слова в байте с самым низким адресом. Предполагая стандартные правила выравнивания для 64-битного компилятора x86 Linux C.
Рассмотрим
Файл 1:
#include <stdio.h>
struct cs {
int count;
unsigned short flags;
};
struct cs gcount;
extern void add_counter( int n );
int main(int c, char *argv[]);
int main(int c, char *argv[]) {
gcount.flags = 0xe700;
gcount.count = 1;
add_counter(42);
printf("count =%d\n", gcount.count);
return 0;
}
Файл 2:
struct cs {
unsigned short flags;
int count;
};
struct cs gcount = {0,0};
void add_counter (int n) {
gcount.count +=n;
}
Если скомпилировано, вывод будет 1
.
Объяснение:
count определяется как сильная глобальная переменная int, поэтому второй файл инициализируется равным {0,0}, здесь порядок еще не имеет значения, поскольку он содержит только нули.
Структура / тип определяется для каждой единицы компиляции, поэтому первый файл использует первое определение для записи в структуру, что означает
gcount.flags = 0xe700; gcount.count = 1;
заставляет память выглядеть как
[e7 00 | 00 00 00 01] где (в обратном порядке) левый верх, а правый - нижняя часть памяти.
(между двумя полями нет заполнения, поскольку short в конце, sizeof сообщит 8B хотя)
при вызове add_counter (42) второй файл будет использовать второе определение cs и смотреть на память как
[e7 00 00 00 | 00 01]
Теперь между двумя полями добавляется 2B, и доступ на запись к счетчику, таким образом, влияет на диапазон
[ e7 00 00 00 | 00 01]
42 равно 0x2a в шестнадцатеричном (2 * 16 + 10) и, следовательно, приведет к
[ e7 2a 00 00 | 00 01]
, преобразовав это обратно в представление, которое имеет первый файл, мы получим
[e7 2a | 00 00 00 01]
и, таким образом, результат равен 1 вместо ожидаемых 43.
Теперь я понимаю общую суть, но я немного запутался, почему мы получаем [*e7 2a* 00 00 | 00 01]
при добавлении 42=0x2a
, а не [*e7 00 00 2a | 00 01]
.
Я ожидаю [*e7 00 00 2a | 00 01]
, потому что мы используем little-endian, то есть самый правильный бит - младший бит. Таким образом, e7
на самом деле представляет здесь самые значимые 8 бит.