я имею Ошибка шины в таком коде:
char* mem_original;
int int_var = 987411;
mem_original = new char [250];
memcpy(&mem_original[250-sizeof(int)], &int_var, sizeof(int));
...
const unsigned char* mem_u_const = (unsigned char*)mem_original;
...
const unsigned char *location = mem_u_const + 250 - sizeof(int);
std::cout << "sizeof(int) = " << sizeof(int) << std::endl;//it's printed out as 4
std::cout << "byte 0 = " << int(*location) << std::endl;
std::cout << "byte 1 = " << int(*(location+1)) << std::endl;
std::cout << "byte 2 = " << int(*(location+2)) << std::endl;
std::cout << "byte 3 = " << int(*(location+3)) << std::endl;
int original_var = *((const int*)location);
std::cout << "original_var = " << original_var << std::endl;
Это хорошо работает несколько раз, распечатывая:
sizeof(int) = 4
byte 0 = 0
byte 1 = 15
byte 2 = 17
byte 3 = 19
original_var = 987411
И тогда это терпит неудачу с:
sizeof(int) = 4
byte 0 = 0
byte 1 = 15
byte 2 = 17
byte 3 = 19
Bus Error
Он построен & работать на ОС Solaris (C ++ 5.12)
Тот же код в Linux (gcc 4.12) & Windows (msvc-9.0) работает хорошо.
Мы можем увидеть:
Так что может быть причиной ошибки шины? Куда мне смотреть?
UPD:
Если я memcpy (…) location
в конце концов original_var
, оно работает. Но в чем проблема *((const int*)location)
?
Это распространенная проблема для разработчиков, не имеющих опыта работы с оборудованием, имеющим ограничения выравнивания, например SPARC. аппаратное обеспечение x86 очень прощение несогласованного доступа, хотя и с влиянием на производительность. Другие типы оборудования? SIGBUS
,
Эта строка кода:
int original_var = *((const int*)location);
вызывает неопределенное поведение. Вы принимаете unsigned char *
и интерпретировать то, на что он указывает как int
, Вы не можете сделать это безопасно. Период. Это неопределенное поведение — по той самой причине, которую вы испытываете.
Вы нарушаете строгое правило наложения имен. Увидеть Что такое строгое правило псевдонимов? Проще говоря, вы не можете ссылаться на объект одного типа как другой тип. char *
не имеет и не может относиться к int
,
Компиляторы Oracle Solaris Studio фактически предоставляют аргумент командной строки, который позволит вам избежать проблем с оборудованием SPARC — -xmemalign=1i
(увидеть https://docs.oracle.com/cd/E19205-01/819-5265/bjavc/index.html). Хотя, если быть честным по отношению к GCC, без этой опции форсирование, которое вы делаете в своем коде, все равно будет SIGBUS
под компилятором студии.
Или, как вы уже заметили, вы можете использовать memcpy()
копировать байты независимо от того, кем они являются — если вы знаете, что исходный объект безопасно копировать в целевой объект — да, бывают случаи, когда это не правда.
При компиляции вашего кода я получаю следующее предупреждение:
main.cpp:19:26: warning: cast from 'const unsigned char *' to 'const int *' increases required alignment from 1 to 4 [-Wcast-align]
int original_var = *((const int*)location);
^~~~~~~~~~~~~~~~~~~~
Это кажется причиной ошибки шины, потому что неправильно выровненный доступ может вызвать ошибку шины.
Хотя сейчас у меня нет доступа к SPARC, чтобы проверить это, из своего опыта работы на этой платформе я вполне уверен, что эта линия — ваша проблема:
const unsigned char *location = mem_u_const + 250 - sizeof(int);
mem_u_const
блок был изначально выделен new
для массива символов. поскольку sizeof(unsigned char)
это 1 и sizeof(int)
4, вы добавляете 246 байтов. Это не кратно 4.
В SPARC процессор может читать 4-байтовые слова, только если они выровнены по 4-байтовым границам. Ваша попытка прочитать неверно выровненное слово является причиной ошибки шины.
Я рекомендую выделить struct
с массивом unsigned char
с последующим int
, а не куча указателей по математике и приведений вроде той, которая вызвала эту ошибку.