Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Использование offsetof, что то не получается.
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Stanislav_S
Итак имеем структуру для теста:
CODE
struct
{
uint16_t data0;
uint16_t data1;
uint16_t data2;
uint16_t data3;
uint16_t data4;
uint16_t data5;
}Data_test;

static uint8_t number;


Далее в программе пытаюсь посмотреть:

CODE
number = offsetof(Data_test, data0);


Получаю в ответ:

CODE
Error[Pe029]: expected an expression C:\Project for ARM\LBR004_V1\Sources\main.c 69
Error[Pe028]: expression must have a constant value C:\Project for ARM\LBR004_V1\Sources\main.c 69
Error[Pe018]: expected a ")" C:\Project for ARM\LBR004_V1\Sources\main.c 69


Компилятор IAR ARM, статьи читал, что делаю не так, или я чего то не понял?

smile3046.gif help.gif

GetSmart
Текст дефайна offsetof можно найти в хидерах и понять как он работает. В offsetof первым аргументом задаётся ТИП структуры. А не сама структура. Обычно перед объявлением структуры (как переменной) объявляется её тип внутри typedef. При объявлении структур (как типа или переменной) можно задаеть ещё один идентификатор, относящийся к типу, сразу после слова struct. Получится struct name1 {...} name2. В дальнейшем name1 с предворяющим словом struct будет означать тип структуры, в которой имя объявлено. Тогда можно написать number = offsetof(struct name1, data0); Естественно, имя name1 заменить на более подходящее.

Уточню, что в компиляторе не проверял. Может быть какой-то заругается, если не реализовали приведение к типу структур вида (struct name).
Stanislav_S
Цитата(GetSmart @ Jan 24 2016, 08:33) *
Можно попробовать написать number = offsetof(struct name1, data0);

Естественно, имя name1 лучше заменить на более подходящее.

Уточню, что в компиляторе не проверял. Может быть заругается, т.к. не реализовали.


В хидере stddef.h макрос описан так:
CODE
#define offsetof(T, member) (__INTADDR__((&((T *)0)->member)))


Пробовал и такой способ - number = offsetof(struct name1, data0); , то же ругается - Error[Pe393]: pointer to incomplete class type is not allowed.
В статьях люди его используют, точно в так же как и я пытаюсь, но вот результат почему - то разный smile3046.gif
GetSmart
Цитата(Stanislav_S @ Jan 24 2016, 16:21) *
В статьях люди его используют, точно в так же как и я пытаюсь, но вот результат почему - то разный smile3046.gif

К примеру в вики непонятно написано о offsetof. Если этот оператор не встроенный в компилятор (не обязан быть встроенным по стандарту) и всегда работает через дефайн, то в него ну никак первым аргументом нельзя передать переменную-структуру или юнион. А если бы оператор был встроенным, то в зависимости от реализации.
Stanislav_S
Ну вот например - offsetof - embedded, по этой статье пробовал применить на практике. Но вот результат у нас разный sm.gif
GetSmart
Вариант из первого поста этой ветки будет работать, но далеко не во всех компиляторах.
например
https://ru.wikipedia.org/wiki/Stddef.h
Цитата
Современные компиляторы реализуют макрос с помощью встроенных функций. Например, реализация gcc выглядит следующим образом[3]:

#define offsetof( st, m ) __builtin_offsetof( st, m )


Точнее может работать. Если в стандарте соответствующей ревизии или расширении, которое поддерживает компилятор внятно написано, что offsetof первым аргументом принимает не только типы, но и переменные.
Сергей Борщ
Полное объявление типа структуры выглядит так:
Код
typedef struct { здесь список членов } имя_типа;
В плюсах есть более короткая запись
Код
struct имя_типа { здесь список членов };

После такого объявления компилятор знает имена, размеры и взаимное расположение членов и вы можете использовать offsetof:
Код
n = offsetof(имя_типа, имя_члена);

Просто объявление struct имя_типа; - неполное (incomplete) объявление типа. После такого объявления компилятор знает, что где-то будет объявлен такой тип и что этот тип будет структурой. Что будет в этой структуре он не знает, максимум, что он может вам позволить после такого объявления - объявить указатель на эту структуру и присваивания с этим указателем. Ни содержания этой структуры, ни размера ее он не знает, поэтому даже инкремента или декремента такого указателя он сделать не может, не говоря уже о доступе к членам этой структуры.

объявление struct { список членов } имя; объявляет структуру безымянного типа и переменную "имя" этого типа. Поэтому вы не можете использовать "имя" в offsetof, ибо это имя переменной, а не типа.

В обычных Сях возможно объявление struct имя_типа { здесь список членов } имя_переменой; Здесь имя_типа - тоже неполное объявление типа, оно позволяет вставить в структуру указатель на нее же (используется для организации связанных списков), но не более того.

В первом сообщении темы нужно было объявить тип структуры и переменную этого типа:
Код
typedef struct
{
  uint16_t data0;
  uint16_t data1;
  uint16_t data2;
  uint16_t data3;
  uint16_t data4;
  uint16_t data5;
}data_test;

data_test Data_test;
struct data_test Data_test1; //можно и так, но тут ключевое слово struct избыточно
И вот после этого можно было использовать offsetof():
Код
number = offsetof(data_test, data0); // тут используется имя типа "data_test", а не имя переменной!
Stanislav_S
Цитата(GetSmart @ Jan 24 2016, 18:16) *
Вариант из первого поста этой ветки будет работать, но далеко не во всех компиляторах.
например
https://ru.wikipedia.org/wiki/Stddef.h
Точнее может работать. Если в стандарте соответствующей ревизии или расширении, которое поддерживает компилятор внятно написано, что offsetof первым аргументом принимает не только типы, но и переменные.

Спасибо что пнули в нужном направлении, никак не мог понять, что действительно нужен тип объекта, а не его реалзация, вот нормально получилось:
CODE
typedef struct
{
uint16_t data0;
uint16_t data1;
uint16_t data2;
uint16_t data3;
uint16_t data4;
uint16_t data5;
}Data_test_t;

Data_test_t Data_test;

Далее -

CODE
number = offsetof(Data_test_t, data5);


number = 10, как и должно быть, проверил еще на целевом union (для которого все затевалось), то же работает. Спасибо! Но опять же получается это именно фишка IARа?
GetSmart
Цитата(Сергей Борщ @ Jan 24 2016, 17:28) *
Полное объявление типа структуры выглядит так:
Код
typedef struct { здесь список членов } имя_типа;
В плюсах есть более короткая запись
Код
struct имя_типа { здесь список членов };

Полное объявление как раз состоит из двух имён. И после такого полного объявления хоть типа, хоть сразу переменной можно ниже по тексту создавать такие же переменные. То есть после такого полного объявления выше по коду можно объявлять так
Код
struct name1 var1,var2;

Смысл первого имени в объявлении структур, юнионов и энумов, а так же здесь указанных переменных, интересно, как иначе можно толковать.

упд
Цитата
В обычных Сях возможно объявление struct имя_типа { здесь список членов } имя_переменой; Здесь имя_типа - тоже неполное объявление типа, оно позволяет вставить в структуру указатель на нее же (используется для организации связанных списков), но не более того.

Возможно более. Т.к. и вне структуры можно создавать через первое имя переменные с типом этой структуры. А это значит, что пара struct name1 должна означать (преобразовываться в) тип структуры и по логике должна съедаться во всех местах, принимающих тип. В т.ч. в type-cast. Иначе это какая-то необоснованная кастрация.
Stanislav_S
Цитата(Сергей Борщ @ Jan 24 2016, 18:28) *
Полное объявление типа структуры выглядит так:

Сергей, спасибо за развернутый ответ - не знал об этой осбенности - думал если объявил структуру, то компилятор знает о ней все. Еще раз спасибо - одним пробелом меньше.
Сергей Борщ
Цитата(GetSmart @ Jan 24 2016, 15:40) *
Полное объявление как раз состоит из двух имён. И после такого полного объявления хоть типа, хоть сразу переменной можно ниже по тексту создавать такие же переменные.
Не совсем понял, а может и я неточно выразился. Да, после такого объявления можно писать struct name1 var1,var2;, а вот писать name1 var1,var2; нельзя, то есть name1 как бы еще не совсем тип. Полным типом он станет в сочетании с ключевым словом struct и мне кажется проще написать один раз typedef, чем засорять потом весь остальной исходник дополнительным struct в каждом месте, где нужно упомянуть тип.
GetSmart
Цитата(Сергей Борщ @ Jan 24 2016, 17:50) *
Полным типом он станет в сочетании с ключевым словом struct...

Станет. Должен становиться. Но у ИАРа видимо своё мнение на этот счёт.

упд
То есть логичнее всего считать первое имя типом структуры из области видимости слова struct. И пара struct name1 должна преобразовываться в полноценный тип, съедаемый везде.
Сергей Борщ
Цитата(GetSmart @ Jan 24 2016, 15:55) *
Станет. Должен становиться. Но у ИАРа видимо своё мнение на этот счёт.

ГЦЦ согласен с ИАРом. Точнее они оба согласны со стандатром, но вам виднее:
Код
// test.c:
struct a
{
    int A;
} A;

a B;

Код
Compiling: test.c
test.c:7:1: error: unknown type name 'a'
a B;
^


P.S. поправил, для полного совпадения
GetSmart
Цитата(Сергей Борщ @ Jan 24 2016, 18:02) *
P.S. поправил, для полного совпадения

О таком применении речи не было. Только в паре со struct. Чуть выше дополнил.
zltigo
QUOTE (Сергей Борщ @ Jan 24 2016, 15:50) *
Полным типом он станет в сочетании с ключевым словом struct и мне кажется проще написать один раз typedef, чем засорять потом весь остальной исходник дополнительным struct в каждом месте, где нужно упомянуть тип.

Поддержу.
Без typedef только объявления анонимных вложенных структур, это все для чего нужны кастрированные варианты.
GetSmart
Какие ваши доказательства? sm.gif

Речь не о удобстве, а о семантике и простоте кода компилятора. Основания кастрации?


Упд.
Основания сам приведу. Если в стандарте изначально type-cast требовал первым словом имя типа, то все ругательства законны. Но в дальнейшей эволюции стало очевидно удобство сути данного спора и в новых версиях могли явно разрешить уточнив, что type-cast можно начинать и со struct/union/enum name, и даже с квалификаторов const, __flash и прочих, допускающихся в декларациях. Конфликта вроде бы не видно.
GetSmart
Странно. Если sizeof "дружит" со struct name в виде
Код
sizeof(struct name)

то не видно препятствий, мешающих использовать такую конструкцию в type-cast. В этом примере допустимы var-name (var-object) и type-name (type-object), а так же type-object via struct/union keywords.

Кроме версии о когда-то сделанной недостаточно точной формулировке.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.