Вопрос

У меня есть определение структуры тестирования следующим образом:

struct test{
    int a, b, c;
    bool d, e;
    int f;
    long g, h;
};

И где-то я использую это так:

test* t = new test;   // create the testing struct
int* ptr = (int*) t;
ptr[2] = 15;          // directly manipulate the third word
cout << t->c;         // look if it really affected the third integer

В моей Windows это работает правильно — печатает 15, как и ожидалось, но безопасно ли это?Могу ли я быть уверен, что переменная находится в том месте памяти, где она должна быть, особенно в случае таких комбинированных структур (например, f в моем компиляторе является пятым словом, но это шестая переменная)?

Если нет, есть ли другой способ напрямую манипулировать членами структуры без фактического наличия конструкции struct->member в коде?

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

Решение

Похоже, вы задаете два вопроса

Безопасно ли рассматривать &test как массив int длиной 3 длины?

Наверное, лучше этого избегать.Это может быть определенное действие в стандарте C++, но даже если это так, маловероятно, что все, с кем вы работаете, поймут, что вы здесь делаете.Я считаю, что это не поддерживается, если вы читаете стандарт, из-за возможности заполнения структур, но я не уверен.

Есть ли лучший способ получить доступ к участнику без его имени?

Да.Попробуйте использовать смещение макрос/оператор.Это обеспечит смещение памяти для конкретного элемента внутри структуры и позволит вам правильно расположить точку на этом элементе.

size_t offset = offsetof(mystruct,c);
int* pointerToC = (int*)((char*)&someTest + offset);

Другой способ - просто взять адрес c напрямую.

int* pointerToC = &(someTest->c);

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

Нет, ты не можешь быть уверен. Компилятор может вводить отступы между членами структуры.

Добавить в ответ JaredPar , еще один вариант только в C ++ (не просто C) создать объект указатель на член:

struct test
{
  int a, b, c;
  bool d, e;
  int f;
  long g, h;
};

int main(void)
{
  test t1, t2;

  int test::*p;  // declare p as pointing to an int member of test
  p = &test::c;  // p now points to 'c', but it's not associating with an object
  t1->*p = 3;    // sets t1.c to 3
  t2->*p = 4;    // sets t2.c to 4

  p = &test::f;
  t1->*p = 5;    // sets t1.f to 5
  t2->*p = 6;    // sets t2.f to 6
}

Возможно, вы ищете макрос offsetof . Это даст вам смещение байта члена. Затем вы можете манипулировать членом с этим смещением. Обратите внимание, что этот макрос зависит от реализации. Включите stddef.h , чтобы заставить его работать.

Вероятно, это небезопасно и на 100% не читается; что делает такой код неприемлемым в реальном производственном коде.

используйте методы set и boost :: bind для функтора create, который изменит эту переменную.

Помимо проблем с отступами / выравниванием, которые возникли в других ответах, ваш код нарушает строгие правила создания псевдонимов, что означает, что он может нарушаться для оптимизированных сборок (не уверен, как MSVC делает это, но GCC -O3 будет перерыв на этот тип поведения). По сути, поскольку test * t и int * ptr имеют разные типы, компилятор может предположить, что они указывают на разные части памяти, и он может переупорядочивать операции.

Рассмотрим эту незначительную модификацию:

test* t = new test;
int* ptr = (int*) t;

t->c = 13;
ptr[2] = 15;
cout << t->c;

Выход в конце может быть 13 или 15 , в зависимости от порядка операций, которые использует компилятор.

В соответствии с пунктом 9.2.17 стандарта фактически допустимо приводить указатель на структуру к указателю на его первый член, при условии, что структура является POD :

  

Указатель на объект POD-struct,   соответствующим образом преобразованы с использованием   reinterpret_cast, указывает на его   первоначальный член (или если этот член   битовое поле, то к единице, в которой   оно проживает) и наоборот. [Заметка:   Поэтому может быть безымянным   заполнение внутри объекта POD-struct,   но не в начале, по необходимости   добиться соответствующего выравнивания. ]

Однако стандарт не дает никаких гарантий относительно структуры структур - даже структур POD - за исключением того, что адрес более позднего элемента будет больше, чем адрес более раннего элемента, при условии, что нет спецификаторов доступа (< code> private: , protected: или public: ) между ними. Таким образом, обработка начальной части вашего struct test как массива из 3 целых чисел является технически неопределенным поведением.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top