Допустим у нас есть функция, которая принимает в себя указатель. Мы знаем, что в указателе лежит нуль-терминальная строка, а за ней 4-байтное целое. Задача — вывести в консоль строку и целое. Решить можно вот так:
Довольно тривиальная задача, не так ли? Проверяем на компе (x86), все ОК. Загружаем на борду с ARM. И, не успев выстрелить себе в ногу, наступаем на грабли. В зависимости от содержания строки, целое значение выводится то нормальным, то кривым. Поверяем указатели, проверяем память, на которые они указывают. Все в норме.
Подмечаем, что целое выводится ровно, когда длина строки равна 3, 7, 11, ..., 4*n-1. Ага. По внимательней смотрим на память и на вывод в «кривых» случаях. Например, если память выглядит так:
Адрес:
Данные:
На выходе мы получаем строку «1111» и целое 0x00000100 вместо 0x00000001.
Вывод: Несмотря на то, что выражением *value мы обращаемся по указателю 0x05, данные нам возвращаются как-будто обращение происходит по указателю 0x04 (или другому кратном�� 4).
Так как правильно решить такую задачу? А вот так:
В таком случае все всегда на своих местах.
Спасибо за внимание!
UPD: Исправил очевидную ошибку.
void foo(void* data_ptr) { //Ставим указатель на строку на начало данных char* str = (char*)data_ptr; //А указатель на целое смещаем на длину строки и еще один байт int* value = (int*)(str+strlen(str)+1); //и выводим содержимое указателей printf("%s %d", str, *value); }
Довольно тривиальная задача, не так ли? Проверяем на компе (x86), все ОК. Загружаем на борду с ARM. И, не успев выстрелить себе в ногу, наступаем на грабли. В зависимости от содержания строки, целое значение выводится то нормальным, то кривым. Поверяем указатели, проверяем память, на которые они указывают. Все в норме.
Подмечаем, что целое выводится ровно, когда длина строки равна 3, 7, 11, ..., 4*n-1. Ага. По внимательней смотрим на память и на вывод в «кривых» случаях. Например, если память выглядит так:
Адрес:
|0x00|0x01|0x02|0x03|0x04|0x05|0x06|0x07|0x08|
Данные:
|0x31|0x31|0x31|0x31|0x00|0x01|0x00|0x00|0x00|
На выходе мы получаем строку «1111» и целое 0x00000100 вместо 0x00000001.
Вывод: Несмотря на то, что выражением *value мы обращаемся по указателю 0x05, данные нам возвращаются как-будто обращение происходит по указателю 0x04 (или другому кратном�� 4).
Так как правильно решить такую задачу? А вот так:
void foo(void* data_ptr) { int value; //Выделяем переменную на стеке char* str = (char*)data_ptr; memcpy(&value, str+strlen(str)+1, sizeof(int)); //копируем в нее данные printf("%s %d", str, value); //выводим данные }
В таком случае все всегда на своих местах.
Спасибо за внимание!
UPD: Исправил очевидную ошибку.