mysol 0 11 мая, 2014 Опубликовано 11 мая, 2014 (изменено) · Жалоба Здравствуйте, товарищи! Прошу помочь разобраться в проблеме. Сам новичок и для написания программы решил разобраться в такой теме как "typedef struct", которая очень полезна при реализации различных интерфейсов (spi, ethernet и прочее). Написал простенькую программу, дабы протестировать и найти возможные подводные камни. Код следующий void f1(uint16_t *f1_var1); typedef struct type1 { uint8_t var1; uint8_t var2; } type1_t; int __main(void) { type1_t *main_var; main_var->var1 = 0xFF; main_var->var2 = 0xFF; f1((uint16_t*)main_var); } void f1(uint16_t *f1_var1) { *f1_var1 = *f1_var1>>1; } Суть программы заключается в формировании пакета данных, состоящего из двух наборов данных (в данном случае var1 и var2) формата uint8_t вызов функции, которая эти данные обрабатывает. Проблема заключается в том, что данные 0xFF не записываются в var1 и var2. С чем это связанно не знаю. Тут значения переменных на этапах отладки Прошу помочь с проблемой. Изменено 11 мая, 2014 пользователем MySOL Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Палыч 10 11 мая, 2014 Опубликовано 11 мая, 2014 · Жалоба Вы забыли свою структуру где либо разместить (выделить под неё память). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kolobok0 0 11 мая, 2014 Опубликовано 11 мая, 2014 (изменено) · Жалоба .. Прошу помочь... ответ прозвучал уже, ну и ышо пять копеек: о выравнивании не забудьте. либо прямо в коде сохраняете старое, ставите прагмой новое, после возвращаете старое. либо глобально на весь проект через ключики компиляции... Изменено 11 мая, 2014 пользователем kolobok0 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KnightIgor 2 11 мая, 2014 Опубликовано 11 мая, 2014 · Жалоба typedef struct type1 { uint8_t var1; uint8_t var2; } type1_t; int __main(void) { type1_t main_var; main_var.var1 = 0xFF; main_var.var2 = 0xFF; f1(&main_var); } void f1(type1_t *f1_var1) { f1_var1->var1 >>= 1; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mysol 0 11 мая, 2014 Опубликовано 11 мая, 2014 · Жалоба Вы забыли свою структуру где либо разместить (выделить под неё память). Уважаемый, вы не могли бы пояснить как это делается? Просто я впервые слышу про такое. ответ прозвучал уже, ну и ышо пять копеек: о выравнивании не забудьте. либо прямо в коде сохраняете старое, ставите прагмой новое, после возвращаете старое. либо глобально на весь проект через ключики компиляции... Простите, но я вас немного не понял. Если можете, ткните носом в статейку, где можно про это почитать, что бы вас не утруждать typedef struct type1 { uint8_t var1; uint8_t var2; } type1_t; int __main(void) { type1_t main_var; main_var.var1 = 0xFF; main_var.var2 = 0xFF; f1(&main_var); } void f1(type1_t *f1_var1) { f1_var1->var1 >>= 1; } По-моему вы ошиблись=) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 11 мая, 2014 Опубликовано 11 мая, 2014 · Жалоба когда вы объявляется my_str * str; str - это указатель на структуру, на место в памяти где она лежит, но сам по себе указатель ничто, структуры нет. my_str str; так вы создадите структуру и сможете обращаться к ее полям как str.field, то есть через точку. далее можно сделать указатель my_str *str2 = &str; и уже обращаться к полям через стрелку str2->field, при это такое обращение будет к полю именно первой структуры str. структуры периферии проца описаны через указатели так (условно) GPIO_STR *PORT1 = (GPIO_STR *) 0x434002300; потому что в памяти уже есть данные лежащие как поля в структуре, это собственно регистры управляющие периферией, и вы создаете явный указатель на эту область памяти Простите, но я вас немного не понял. Если можете, ткните носом в статейку, где можно про это почитать, что бы вас не утруждать есть разное выравнивание памяти, и иногда структура вида struct... { char field1; char field2; } может быть в памяти представлена 2 байтами, лежащими друг за другом, а может 8 байтами, где в 0 лежит field1, потом 3 байта пропуска, и в 4 лежит filed2. Это сделано потому что некоторые процы умеют брать данные только 32 битными или 16 битными словами, и в принципе не могут обращаться в области памяти с адресами не кратными их размеру слова. так вот есть специальные слова позволяющие подсказывать как создавать структуру, типа __packed По-моему вы ошиблись=) он не ошибся, он заменил указатель структуры на экземпляр type1_t main_var; вместо ваших type1_t *main_var; и соответственно вызовы через стрелку на вызовы через точку. а также добавил функцию обработки данных структуры через указатель... И в целом это все не относиться к кейлу или арму, это вообще вопросы базового знания языка С.... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mysol 0 11 мая, 2014 Опубликовано 11 мая, 2014 (изменено) · Жалоба .... Благодарю, что указали на ошибку при инициализации указателя! Благодарю всех за помощь! Проблема решена Изменено 12 мая, 2014 пользователем IgorKossak бездумное цитирование Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 11 мая, 2014 Опубликовано 11 мая, 2014 · Жалоба Выравнивание - с этим ничего не сделаешь, с этим надо жить:).. вот на пальцах смысл. берем проц типа кортекс м0, если не ошибаюсь этот процессор не умеет обращаться к памяти без выравнивания. делаем в нем структуру struct str { int8_t A; int8_t B; } он выделяет 8 байт памяти и кладет данные A 0 0 0 B 0 0 0 работаем внутри проца и все счастливы. Теперь мы добавляем какой-то интерфейс с внешним миром, например с PC или делаем сохранение параметров в память. Радостно делаем функцию которая посылает данные, с указателем на данные и размером данных, вызываем SaveSendData(MY_STR, 2) и что? облом, структура то не 2 а 8 байт, половина не сохранилась. вызываем SaveSendData(MY_STR, sizeof(MY_STR)), все хорошо, но в памяти отъели 8 байт если мы про это не знаем может затереть данные. Теперь на РС делаем ответную структуру struct str{char A; char B} и что дальше? в компе то нет выравнивания, структура 2 байта, прямое копирования и пересылка - опять облом... казалось, ок, если такая структура плохо, делаем ее struct __packed str { int8_t A; int8_t B; } пересылка - сохранение в память - прием на компе - супер! вот оно счастье, но! Проц то не умеет обращаться в не выровненые адреса, и обращение my_str.B будет всегда вести в my_str.A, хоть убейся об него, пишите В, меняете А, читаете В, получаете А. И один способ записать или изменить В, это считать 32 бита A,B,0,0, вырезать маской нужную часть, сдвинуть и считать данные, для изменения обратно, считать 32 бита, масками изменить нужный кусок, записать обратно... То есть либо теряем скорость, либо удобство, и об этом надо думать и понимать что у вас происходит.... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 242 11 мая, 2014 Опубликовано 11 мая, 2014 · Жалоба Не очень понял как мешает выравнивание структуре struct str { int8_t A; int8_t B; } в ней-же все элементы - байт. На любом CPU, который умеет работать с байтами (и PC и Cortex-M0), с такой структурой никаких проблем выравнивания не будет. в компе то нет выравнивания В компе-то - нет, но в си-компиляторах есть. Вне зависимости от CPU. Насчёт пакованных структур - тоже не понял. Компиляторы (IAR во всяком случае) при работе с пакованными структурами на CPU не умеющем невыровненный доступ, знают это прекрасно и выполняют доступ к членам структуры в соответствии с величиной пакованности (1,2,...) - разбивают обращения на несколько 8-и или 16-и-битных (загляните в листинг!). И си-программисту эта кухня невидима. Скорость конечно будет ниже. Но на удобство почти никак не повлияет. Единственно - будет проблема с указателями на такие структуры. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 11 мая, 2014 Опубликовано 11 мая, 2014 · Жалоба да..., вот потому и хорошо даже для себя много раз прописывать даже очевидные вещи, я правда был не корректен и не точен в структуре struct { char A; char B; } наверное, правда, проблем не будет, а в структуре struct { char A; char B; int C; } проблемы точно должны быть. Также должны быть проблемы между 2 соседними структурами, в массиве, например, если думать что начало второй через sizeof(str) после начала первой.... В компе-то - нет, но в си-компиляторах есть. Вне зависимости от CPU. Тут я опять не совсем корректен. Я имел ввиду глобально, что обычно на компьютере в силу архитектуры их процов (блин сейчас правда и для компа процов уже не 1, но будем мыслить шире) обычно (по умолчанию) память пакована до байтовой границы. Опять же более строго для все обще принятых компиляторов и языков. Естественно спец компиляторы под платформу с С язык скрывают всю эту кухню, и никогда написав в коде str.B, вы не измените и не получите соседнего поля, но за этим обращением может быть скрыто много действий, то есть как минимум оно может стать не атомарным. Сейчас процы все быстрее, и пару тактов туда суда погоды не делают, но не атомарность может здорово что-то загадить при наличии прерываний. А в 32 битном микроблайзе попытка копирования или печати массива с 1, 2, 3 адреса всегда копировала или печатала его с 0, это не относится к упаковке, но относиться к выравниванию. Иногда разбирая или наоборот заполняю структуру удобнее копировать ее не по полям, а большими кусками из других кусков, данных и памяти, и при таких операциях надо всегда четко знать что как лежит. Мне кажется что кто пишет под процы, должен очень хорошо знать эту кухню изнутри, мы особая каста это не в виндус thread-ов наделать, а потом писать в форумах что программ без ошибок не бывает. И я пытался на примерах (возможно не очень корректно изложенных) показать с чем мы имеем дело. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 242 11 мая, 2014 Опубликовано 11 мая, 2014 · Жалоба struct { char A; char B; int C; } проблемы точно должны быть. Также должны быть проблемы между 2 соседними структурами, в массиве, например, если думать что начало второй через sizeof(str) после начала первой.... В чём-же? :rolleyes: Ну разве, что если использовать её на разных системах, с разным размером int.... Вам известно, что в структурах (классах) си по умолчанию выполняется выравнивание (вне зависимости от CPU; это правило языка си)? Ну только если конечно не предпринять спец. мер (pack). Также и начало второй в массиве - всегда после sizeof() от начала первой как ни странно... :rolleyes: Размер (sizeof()) также выравнивается на размер выравнивания структуры (который в свою очередь равен размеру максимального члена). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 11 мая, 2014 Опубликовано 11 мая, 2014 · Жалоба о том вроде и беседуем... Вы уверены что все проекты что вы создаете в кейле или других средах, под разные процы по умолчанию упакованы до байта, перефразирую, уверены что нигде не задается метод пакования отличный от побайтно? А вы уверены что упакованные 6 байтные структуры идут в памяти через 6 байт на всех типах процов? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 242 12 мая, 2014 Опубликовано 12 мая, 2014 · Жалоба Хм... Я разве где-то подобное говорил?? Я вообще-то говорил почти противоположное: 1. Структуры в си по умолчанию не упакованные. 2. Выравнивание структуры равно выравниванию максимального члена структуры. 3. Максимальное выравнивание для встроенных типов данных как правило не превышает основной разрядности CPU (хотя это не могу утверждать с полной уверенностью). (т.е. - если CPU 32-разрядный, то выравнивание 64-битного встроенного типа будет всё равно ==32). Про упакованность - тоже Вы что-то не поняли. Я как раз писал, что пакование может выполняться не обязательно до уровня байт, может быть до уровня 16-бит или др. см. #pragma pack(push, N) в IAR к примеру. Пример IAR: #pragma pack(push, 2) struct T { u32 a; u8 b; }; #pragma pack(pop) В данной структуре будет sizeof(T)==6. И выравнивание её будет равно ==16бит. И вообще - упаковка не входит в язык си и может выполняться по-разному на разных компиляторах. А вы уверены что упакованные 6 байтные структуры идут в памяти через 6 байт на всех типах процов? Очевидно, что в си, если имеется структура (не важно - пакованная или нет), то в массиве элементов этой структуры начало каждого следующего элемента будет находиться по смещению sizeof() от предыдущего. А вот уже величина этого sizeof(T) будет зависеть от наличия pack() в её атрибутах и величины пакования этого самого pack(). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 12 мая, 2014 Опубликовано 12 мая, 2014 · Жалоба Что-то я совсем потерялся.... Что в процах с 32 битным выравниванием данных прямые бездумные обращения к памяти чреваты - это точно. В таких процах создание массивов элементов размера не кратного 32 битам и бездумное обращение с ними как с памятью - тоже чревато. А вот объяснения и примера я чет хорошего придумать не могу%(.... вы все врем меня стандартами языка придавливаете:(.... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 12 мая, 2014 Опубликовано 12 мая, 2014 · Жалоба А вот объяснения и примера я чет хорошего придумать не могу%(.... вы все врем меня стандартами языка придавливаете:(....Объяснения чего? Чреватости? Пожалуйста: MSP430, 16-битный, доступ к 16-битному значению по невыровненному адресу игнорирует младший бит адреса, результат - идет обращение к одному байту переменной и одному сосенднему. ARM7TDMI - обычно аналогично. В Cortex-M0 - исключение HardFault. Cortex-M3 - Исключение UsageFault или нормальный доступ для некоторых инструкций в зависимости от бита UNALIGN_TRP, для остальных инструкций - UsageFault. Пример в первом же сообщении этой темы: void f1(uint16_t *f1_var1); typedef struct type1 { uint8_t var1; uint8_t var2; } type1_t; ... type1_t *main_var; ..... f1((uint16_t*)main_var); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться