Что такое общий макрос C/C++ для определения размера члена структуры?

StackOverflow https://stackoverflow.com/questions/1400660

  •  05-07-2019
  •  | 
  •  

Вопрос

Как в C/C++ определить размер переменной-члена структуры без необходимости определять фиктивную переменную этого типа структуры?Вот пример того, как сделать это неправильно, но он показывает намерение:

typedef struct myStruct {
  int x[10];
  int y;
} myStruct_t;

const size_t sizeof_MyStruct_x = sizeof(myStruct_t.x);  // error

Для справки: вот как найти размер «x», если вы сначала определяете фиктивную переменную:

myStruct_t dummyStructVar;

const size_t sizeof_MyStruct_x = sizeof(dummyStructVar.x);

Однако я надеюсь избежать необходимости создавать фиктивную переменную только для того, чтобы получить размер «x».Я думаю, что есть умный способ преобразовать 0 в myStruct_t, чтобы помочь найти размер переменной-члена «x», но прошло достаточно много времени, и я забыл детали, и, похоже, не могу найти хороший поиск в Google по этому вопросу. .Вы знаете?

Спасибо!

Это было полезно?

Решение

В C++ (как говорят теги) ваш код «фиктивной переменной» можно заменить следующим:

sizeof myStruct_t().x;

Объект myStruct_t не будет создан:компилятор обрабатывает только статический тип операнда sizeof, но не выполняет выражение.

Это работает в C, а в C++ лучше, потому что это также работает для классов без доступного конструктора без аргументов:

sizeof ((myStruct_t *)0)->x

Другие советы

Я использую следующий макрос:

#include <iostream>
#define DIM_FIELD(struct_type, field) (sizeof( ((struct_type*)0)->field ))
int main()
{
    struct ABC
    {
        int a;
        char b;
        double c;
    };
    std::cout << "ABC::a=" << DIM_FIELD(ABC, a) 
              << " ABC::c=" << DIM_FIELD(ABC, c) << std::endl;

    return 0;
}

Хитрость заключается в том, что 0 рассматривается как указатель на вашу структуру.Это решается во время компиляции, поэтому это безопасно.

Вы можете легко сделать

sizeof(myStruct().x)

Поскольку параметр sizeof никогда не выполняется, вы на самом деле не создадите этот объект.

Любой из них должен работать:

sizeof(myStruct_t().x;);

или

myStruct_t *tempPtr = NULL;
sizeof(tempPtr->x)

или

sizeof(((myStruct_t *)NULL)->x);

Потому что sizeof оценивается во время компиляции, а не во время выполнения, у вас не возникнет проблем с разыменованием NULL-указателя.

В C++11 это можно сделать с помощью sizeof(myStruct_t::x).C++11 также добавляет станд::деклвал, который можно использовать для этого (помимо прочего):

#include <utility>
typedef struct myStruct {
  int x[10];
  int y;
} myStruct_t;

const std::size_t sizeof_MyStruct_x_normal = sizeof(myStruct_t::x);
const std::size_t sizeof_MyStruct_x_declval = sizeof(std::declval<myStruct_t>().x);

Из заголовка моего служебного макроса:

#define FIELD_SIZE(type, field) (sizeof(((type *)0)->field))

вызывается так:

FIELD_SIZE(myStruct_t, x);  
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top