Объявляем 2 крайне похожие структуры: Код (C++): struct ThreeHour { time_t Data; //прогноз на Дату "2014-10-10 21:00' int16_t T; //Температура int16_t TT; //Температура Min или Max int8_t H; //Влажность int16_t P; //Давление int8_t WS; //Скорость ветра char WD[4]={0};//Направление int8_t Cloud; //Облачность в % int16_t RainVal; //количество осадков (*100), 0 - если нет, - снег + дождь int16_t SymNum; }; struct ThreeHourExt { time_t Data; //прогноз на Дату "2014-10-10 21:00' int16_t T; //Температура int16_t TT; //Температура Min или Max int16_t H; //Влажность int16_t P; //Давление int16_t WS; //Скорость ветра char WD[4]={0};//Направление int16_t Cloud; //Облачность в % int16_t RainVal; //количество осадков (*100), 0 - если нет, - снег + дождь int16_t SymNum; }; struct ThreeHour whp3h[8]; struct ThreeHourExt whp3he[8]; В коде, например в setup() пишем Код (C++): void setup(void) { char Buf[50]; Serial.begin(115200); Serial.println("--------------------------------------------"); sprintf(Buf,"Тип time_t - %u байт\r\n", sizeof(time_t)); Serial.print(Buf); sprintf(Buf,"Тип int8_t - %u байт\r\n", sizeof(int8_t)); Serial.print(Buf); sprintf(Buf,"Тип int16_t - %u байт\r\n", sizeof(int16_t)); Serial.print(Buf); sprintf(Buf,"Тип whp3h[0] - %u байт\r\n", sizeof(whp3h[0])); Serial.print(Buf); sprintf(Buf,"Тип whp3he[0] - %u байт\r\n", sizeof(whp3he[0])); Serial.print(Buf); Serial.println("--------------------------------------------"); } Заливаем в ESP_шку и на выходе получаем следующее: Код (C++): -------------------------------------------- Тип time_t - 4 байт Тип int8_t - 1 байт Тип int16_t - 2 байт Тип whp3h[0] - 24 байт Тип whp3he[0] - 24 байт -------------------------------------------- Если же залить в ATmeg_у, то увидим ожидаемое: Код (C++): -------------------------------------------- Тип time_t - 4 байт Тип int8_t - 1 байт Тип int16_t - 2 байт Тип whp3h[0] - 21 байт Тип whp3he[0] - 24 байт -------------------------------------------- Не пойму, почему ESP для этих структур, дает одинаковый размер?
Процессоры разные, в ESP - 32-х разрядный, компилятор выравнивает данные до четного. Если нужно, можно отключить выравнивание через #pragma pack
Да, согласен, был неправ. Значит все-таки до четного. Кстати. если автор чуть поменяет порядок полей, например соберет все uint8_t рядом - размер структуры уменьшится
Вопрос, что более приоритетно. Скорость доступа, размер или совместимость с существующими структурами ( например структура данных передается на другое устройство)
В данном случае, для меня 21 или 24 байта - не принципиально. На текущей железяке, которая получала прогноз с инета, пакет занимает 21 байт. Решил перенести данный функционал на ESP и столкнулся с тем, что данные отправленные на дисплей через nRF24 искажены, начал разбираться с причиной. Про выравнивание была мысль, но подумал - какого хрена? ведь вроде бы типы данных в структуре четко обЪявлены. Ну что ж, изменю размер структуры на 24 байта на всех устройствах.
Так а не проще ли отключить выравнивание на ESP. В принципе, правильнее всегда отключать выравнивание, если структура данных используется для взаимодействия с чем либо, и требуется определенная размерность данных для корректного взаимодействия. Код для Меги и ESP будет выглядеть так, сюрпризов от компилятора при этом не будет: Код (C++): #pragma pack(push,1) struct ThreeHour { time_t Data; //прогноз на Дату "2014-10-10 21:00' int16_t T; //Температура int16_t TT; //Температура Min или Max int8_t H; //Влажность int16_t P; //Давление int8_t WS; //Скорость ветра char WD[4]={0};//Направление int8_t Cloud; //Облачность в % int16_t RainVal; //количество осадков (*100), 0 - если нет, - снег + дождь int16_t SymNum; }; struct ThreeHourExt { time_t Data; //прогноз на Дату "2014-10-10 21:00' int16_t T; //Температура int16_t TT; //Температура Min или Max int16_t H; //Влажность int16_t P; //Давление int16_t WS; //Скорость ветра char WD[4]={0};//Направление int16_t Cloud; //Облачность в % int16_t RainVal; //количество осадков (*100), 0 - если нет, - снег + дождь int16_t SymNum; }; #pragma pack(pop) struct ThreeHour whp3h[8]; struct ThreeHourExt whp3he[8];
AlexVS получилось у вас? Тоже самая проблема при замене меги на esp wemos данные по nrf приходят искаженные.
Доброго времени суток: Вот имею: Код (C++): typedef struct { int64_t TimeStamp; int32_t T1; int32_t T2; uint8_t flag1; uint8_t flag2; .... } DATA2; Всё нормально вроде... но некая структура (допустим эта) передаётся в TCP пакете... И всё нормально вроде. Это если две машины одинаковы... но если одна из них ARM, а другая x86, то размер передаваемого пакета разный и #pragma pack не помогает. Спасает одно - опытным путём добавляю параметры в структуру таким образом делаю их идентичными как для приёма, таки для передачи. Кстати часто выручает то, что высокую размерность переменных в структуре размещаю первыми и по её убыванию остальные так: Код (C++): uint64_t uint32_t float uint16_t int16_t int8_t но как говорил не всегда помогает что с #pragma pack, так и без оного. Это при том, что на разных машинах GCC... но если ещё для какой-то машины VisualStudio(там где Windows), то дела совсем не весёлые. Пытался всё размещать просто в массиве типа: Код (C++): #define _szB 32 uint8_t buff[_szB]; ... #define _b_TimeStamp 0x00 #define _b_T1 0x04 ... и так двлее и после всего так: Код (C++): uint64_t TS = (*(uint64_t*)(&buff[_b_TimeStamp])); ... и так далее не всегда помогает. Думаю потому как надо адресовать кратно размерности параметра, что часто подтверждается... хоть и не всегда(считать размерность приходится). Особенно если обмен между разными платформами... и соответственно собраны разными компиляторами. В моём случае надо проверять размерность/организацию структуры на разных машинах... #pragma pack работает по разному на разных компиляторах(платформах)
Такое может быть, так как на некоторых платформах такие типы как uint32 uint64 обязательно должны быть выравнены. Но если Вы сами все пакуете в байтовый массив - то никаких искажений быть не может, в этом случае ищите ошибку в коде.
Я с таким не сталкивался - #pragma pack - всегда решался вопрос если переменные определены через uint8_t, а не unsigned char.
Именно так. uint64_t, int64_t я выравнивал кратно 8. in32_t, uint32_t, float кратно 4 соответственно и т.д... о чём и говорил ранее. Иногда приходилось вставлять "пустые" переменные... к примеру после int64_t пустая int32_t(как пример) аж 2 штуки. потому как одним компилятором будет добавлен сам, а другим нет. По смыслу это по другому... после int64_t потом int32_t и потом int16_t (то же как пример). Хотя я мог не верно указывать #pragma pack (в некоторых компиляторах он с числовым значением выравнивания, в других нет - а просто #pragma pack). Вот и такой бардак, когда с одного контроллера допустим UNO-1019(VisualStudio) по TCP посылаются пакеты на PC-Debian(GCC) ну или с MOXA IA-240LX(GCC) на PC-Debian(GCC). Как видите устройства разные и приходится делать идентичные по содержанию структуры. И пока я не выработал для себя универсальный подход для решения этого.
Как говорил на разных машинах по разному... не всегда срабатывает. И #pragma pack в разных комптляторах мало того что работают по разному, так ещё и синтаксис разный. Довольно не удобно. Делаешь заголовочный файл, переносишь на другую машину и там ещё допиливаешь под оную.
В 11 сообщении я упомянул этот вариант, работает. Но очень не удобно иметь набор #define бла-бла-бля. Благо привык к gedit, а не среды разработки... вообще-то думал, что тема закрыта... а я только подчеркнул необходимость проверки соответствия структур на разных платформах. Чисто для того что бы не "входить в ступор" при вопросах работоспособности при обмене данными на разных устройствах.
Работать то оно должно, главное самому не ошибиться в расчетах. Последнюю строчку, в таком варианте, можно проще записать. uint64_t TS = *( (uint64_t *) (buff + _b_TimeStamp));
Код (C++): uint64_t TS = (* (uint64_t *) (&buff + _b_TimeStamp)); //или uint8_t *b = &buff[0]; uint64_t TS=(*(uint64_t*)(b + _b_TimeStamp));