LINUX.ORG.RU

C: всегда ли элементы структуры хранятся последовательно?


0

0
struct A
{
  // c99
  int a;
  bool b;
  bool c;
};

*Всегда* ли элементы структур расположены в памяти последовательно? Могу ли я адресоваться к полю экземпляра структуры используя адресацию относительно первого поля?

Что-то вроде (псевдо-код):

struct A s;
...
  (bool)(s + addr_of_field(s, 0)) = false;

Если это всегда верно, то применимо ли это и к ARM в том числе?

Спасибо.

anonymous

> *Всегда* ли элементы структур расположены в памяти последовательно?

а какая разница? хоть с дырками. хоть параллельно :-)

> Могу ли я адресоваться к полю экземпляра структуры используя адресацию относительно первого поля?

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

> (bool)(s + addr_of_field(s, 0)) = false;

такое наверно и не скомпилируется даже. ты наверно имелл ввиду

*((bool*)(s + addr_of_field(...))) = false ?

gods-little-toy ★★★
()

Примеров, когда это не так ононимусу неизвестно. Если будешь учитывать выравнивание, можешь. Но нафига?

anonymous
()
Ответ на: комментарий от gods-little-toy

> *((bool*)(s + addr_of_field(...))) = false ?

Да, именно так.

Вот только это не работает как надо:

struct A
{
    int a;
    bool b;
    bool c;
};


#define b2s(x) (x ? "true" : "false")
#define printA(x) printf("a = %d, b = %s. c = %s\n", x.a, b2s(x.b), b2s(x.c))

...
    struct A a;

    a.a = 10;
    a.b = true;
    a.c = true;

    printA(a);

    // trying to change a value of the third field named 'c'
    *(bool *)(((struct A *)&a) + (sizeof(int) + sizeof(bool))) = false;

    // value of 'c' hasn't been changed
    printA(a);

anonymous
()
Ответ на: комментарий от anonymous

> Если будешь учитывать выравнивание, можешь.

Можно, пожалуйста, про выравнивание по-подробней? Можно носом в доку :)

> Но нафига?

Что бы избежать copy&paste в коде. Есть 2 функции, которые получают структуру, инвертируют значение её поля и куда-то записывают обновленную структуру. Оба поля имеют одинаковый тип, но называются по-разному -- вот и хочется сделать re-use кода.

На крайний случай придется использовать cpp, чтобы свести копипаст кода к минимуму.

anonymous
()
Ответ на: комментарий от anonymous

> *(bool *)(((struct A *)&a) + (sizeof(int) + sizeof(bool))) = false;

дык ясен песен такое не работает. Читай что происходит при сложении указателя на структуру и числа... ты тыкаешься в адрес А + 8 размеров структуры... а не +8 байт...

*(bool *)(((сhar*)&a) + (sizeof(int) + sizeof(bool))) = false;

.

gods-little-toy ★★★
()
Ответ на: комментарий от anonymous

>Можно, пожалуйста, про выравнивание по-подробней? Можно носом в доку :)
 
bash-3.2# cat 4.c
#include <stdio.h>

struct A
{
    char a;
    int b;
};

int main(void) {
    struct A a;

    printf("%u\n", &a.a);
    printf("%u\n", (int)&a.a + sizeof(char));
    printf("%u\n", &a.b);

    return 0;
}
bash-3.2# gcc -std=c99 4.c && ./a.out
3216977756
3216977757
3216977760

Так что завязывай с таким кодом.
>*(bool *)(((сhar*)&a) + (sizeof(int) + sizeof(bool))) = false; 

koTuk
()

>*Всегда* ли элементы структур расположены в памяти последовательно?

нет, скорее даже очень редко. впрочем есть __attribute__((packed))

>Могу ли я адресоваться к полю экземпляра структуры используя адресацию относительно первого поля?


можешь:
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})

псевдокод:
container_of(&s.a, struct A, a).b = false;

generatorglukoff ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.