Перейти к содержанию
    

Использование offsetof, что то не получается.

Итак имеем структуру для теста:

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;

 

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

 

number = offsetof(Data_test, data0);

 

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

 

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: :help:

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Уточню, что в компиляторе не проверял. Может быть какой-то заругается, если не реализовали приведение к типу структур вида (struct name).

Изменено пользователем GetSmart

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно попробовать написать number = offsetof(struct name1, data0);

 

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

 

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

 

В хидере stddef.h макрос описан так:

#define offsetof(T, member)     (__INTADDR__((&((T *)0)->member)))

 

Пробовал и такой способ - number = offsetof(struct name1, data0); , то же ругается - Error[Pe393]: pointer to incomplete class type is not allowed.

В статьях люди его используют, точно в так же как и я пытаюсь, но вот результат почему - то разный :smile3046:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В статьях люди его используют, точно в так же как и я пытаюсь, но вот результат почему - то разный :smile3046:

К примеру в вики непонятно написано о offsetof. Если этот оператор не встроенный в компилятор (не обязан быть встроенным по стандарту) и всегда работает через дефайн, то в него ну никак первым аргументом нельзя передать переменную-структуру или юнион. А если бы оператор был встроенным, то в зависимости от реализации.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну вот например - offsetof - embedded, по этой статье пробовал применить на практике. Но вот результат у нас разный :)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вариант из первого поста этой ветки будет работать, но далеко не во всех компиляторах.

например

https://ru.wikipedia.org/wiki/Stddef.h

Современные компиляторы реализуют макрос с помощью встроенных функций. Например, реализация gcc выглядит следующим образом[3]:

 

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

 

Точнее может работать. Если в стандарте соответствующей ревизии или расширении, которое поддерживает компилятор внятно написано, что offsetof первым аргументом принимает не только типы, но и переменные.

Изменено пользователем GetSmart

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Полное объявление типа структуры выглядит так:

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", а не имя переменной!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вариант из первого поста этой ветки будет работать, но далеко не во всех компиляторах.

например

https://ru.wikipedia.org/wiki/Stddef.h

Точнее может работать. Если в стандарте соответствующей ревизии или расширении, которое поддерживает компилятор внятно написано, что offsetof первым аргументом принимает не только типы, но и переменные.

Спасибо что пнули в нужном направлении, никак не мог понять, что действительно нужен тип объекта, а не его реалзация, вот нормально получилось:

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;

Далее -

 

number = offsetof(Data_test_t, data5);

 

number = 10, как и должно быть, проверил еще на целевом union (для которого все затевалось), то же работает. Спасибо! Но опять же получается это именно фишка IARа?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Полное объявление типа структуры выглядит так:

typedef struct { здесь список членов } имя_типа;

В плюсах есть более короткая запись

struct имя_типа { здесь список членов };

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

struct name1 var1,var2;

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

 

упд

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

Возможно более. Т.к. и вне структуры можно создавать через первое имя переменные с типом этой структуры. А это значит, что пара struct name1 должна означать (преобразовываться в) тип структуры и по логике должна съедаться во всех местах, принимающих тип. В т.ч. в type-cast. Иначе это какая-то необоснованная кастрация.

Изменено пользователем GetSmart

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Полное объявление типа структуры выглядит так:

Сергей, спасибо за развернутый ответ - не знал об этой осбенности - думал если объявил структуру, то компилятор знает о ней все. Еще раз спасибо - одним пробелом меньше.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Полное объявление как раз состоит из двух имён. И после такого полного объявления хоть типа, хоть сразу переменной можно ниже по тексту создавать такие же переменные.
Не совсем понял, а может и я неточно выразился. Да, после такого объявления можно писать struct name1 var1,var2;, а вот писать name1 var1,var2; нельзя, то есть name1 как бы еще не совсем тип. Полным типом он станет в сочетании с ключевым словом struct и мне кажется проще написать один раз typedef, чем засорять потом весь остальной исходник дополнительным struct в каждом месте, где нужно упомянуть тип.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Полным типом он станет в сочетании с ключевым словом struct...

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

 

упд

То есть логичнее всего считать первое имя типом структуры из области видимости слова struct. И пара struct name1 должна преобразовываться в полноценный тип, съедаемый везде.

Изменено пользователем GetSmart

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

ГЦЦ согласен с ИАРом. Точнее они оба согласны со стандатром, но вам виднее:

// 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. поправил, для полного совпадения

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

P.S. поправил, для полного совпадения

О таком применении речи не было. Только в паре со struct. Чуть выше дополнил.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Полным типом он станет в сочетании с ключевым словом struct и мне кажется проще написать один раз typedef, чем засорять потом весь остальной исходник дополнительным struct в каждом месте, где нужно упомянуть тип.

Поддержу.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...