LINUX.ORG.RU

[C] Преобразование указателей на структуры


0

0
#include <stdio.h>

struct s_base
{
  int tag;
};

struct s1
{
  int tag;
  int data;
};

struct s2
{
  int tag;
  float data;
};

int main()
{
  struct s1 a;
  struct s_base *b = (struct s_base *) &a;
  a.tag = 1234;
  if(a.tag != b->tag)
  {
    printf("can never happen\n");
  }
  return 0;
}

У трёх структур общее «начало». Указатели на экземпляры структур s1 и s2 преобразовываются к указателям s_base. Гарантируется ли стандартом Си, что условие внутри if() никогда не выполнится?


[C] Преобразование указателей на структуры

да

P1XeL ()

[C] Преобразование указателей на структуры

Мне вот интересно, какой индусский код вы планируете создать на основе полученной информации.

dn2010 ★★★★★ ()

[C] Преобразование указателей на структуры

нет

Legioner ★★★★★ ()

[C] Преобразование указателей на структуры

не гарантируется. Вообще тут сразу имеет место быть варнинг в строчке

struct s_base *b = (struct s_base *) &a;

warning: dereferencing pointer ‘b’ does break strict-aliasing rules

в стандарте такой случай упоминается как UB.

попробуйте, например:

gcc -O3 -W -Wall your_buggy_program.c

rha ()

Re: [C] Преобразование указателей на структуры

Мне вот интересно, какой индусский код вы планируете создать на основе полученной информации.

Может свою реализацию API сокетов со всеми его sockaddr, sockaddr_in?

mannaz ()

Re: [C] Преобразование указателей на структуры

В XLib такая же ситуация, как и в описанном примере. XEvent и всякие XUnmapEvent, XGraphicsExposeEvent и т.п. сделаны именно по этому принципу. И X Window вроде бы не индусы проектировали.

anonymous ()

Re: [C] Преобразование указателей на структуры

> warning: dereferencing pointer ‘b’ does break strict-aliasing rules

Насколько я знаю, это GCC-специфичное предупреждение, причем оно связано с особенностями оптимизатора - он предполагает, что на одну область памяти не могут одновременно указывать указатели разных типов. Это может сломать оптимизацию, но никак не приводит к UB. Приведение указателей к (void *) такого предупреждения не дает.

Стандарт на этот счет вроде молчит, поправьте, если ошибаюсь.

SilentBob ()

Re: [C] Преобразование указателей на структуры

> Насколько я знаю, это GCC-специфичное предупреждение, причем оно связано с особенностями оптимизатора

оптимизатор оптимизирует (тем более по умолчанию) только тогда когда он уверен, что не изменит поведение корректного кода. Если он ломает код, то будь уверен, что компиляторные ребята ткнут тебя мордой где у тебя UB.

dilmah ★★★★★ ()

[C] Преобразование указателей на структуры

В OpenCV еще на такое полагались

dilmah ★★★★★ ()

Re: [C] Преобразование указателей на структуры

> не гарантируется. Вообще тут сразу имеет место быть варнинг в строчке

Варнинг этот про другое, как я написал раньше.

А вот почему "не гаратнируется"? Размещение в памяти элементов структуры может различаться в зависимости от этих элементов, то есть не быть строго последовательным?

SilentBob ()

Re: [C] Преобразование указателей на структуры

> то есть не быть строго последовательным?

Что ты подразумеваешь под последовательным ? Если выравнивание - то да, могут быть фокусы.

runtime ★★★★ ()

Re: [C] Преобразование указателей на структуры

подразумеваю пример ТС:

struct s1{
int a;
...
}

struct s2{
int a;
...
}

s1 p1 = {...};

s2 *p2 = (void *)p1;

выравнивание может привести к тому, что p1->a и p2->a будут ссылаться на разные области памяти?

SilentBob ()

[C] Преобразование указателей на структуры

Изучайте XLib.h и примеры программирования с XLib, пример практически оттуда срисован. Любое событие можно преобразовать в структуру XAnyEvent

typedef struct {
	int type;
	unsigned long serial;	/* # of last request processed by server */
	Bool send_event;	/* true if this came from a SendEvent request */
	Display *display;/* Display the event was read from */
	Window window;	/* window on which event was requested in event mask */
} XAnyEvent;
например XSelectionClearEvent
XSelectionClearEvent
typedef struct {
	int type;
	unsigned long serial;	/* # of last request processed by server */
	Bool send_event;	/* true if this came from a SendEvent request */
	Display *display;	/* Display the event was read from */
	Window window;
	Atom selection;
	Time time;
} XSelectionClearEvent;

или смешивая их в вместе

typedef union _XEvent {
        int type;		/* must not be changed; first element */
	XAnyEvent xany;
	XKeyEvent xkey;
	XButtonEvent xbutton;
	XMotionEvent xmotion;
 ....................

anonymous ()

[C] Преобразование указателей на структуры

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

anonymous ()

[C] Преобразование указателей на структуры

Не гарантируется. Есть нюансы, но в данном случае надо юзать union. Нет причин не юзать union.

anonymous ()

Re: [C] Преобразование указателей на структуры

> оптимизатор оптимизирует (тем более по умолчанию) только тогда когда он уверен, что не изменит поведение корректного кода.

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

6.3.2.3 Pointers 1 A pointer to void may be converted to or from a pointer to any incomplete or object type. A pointer to any incomplete or object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.

Про UB там тоже есть: 7 A pointer to an object or incomplete type may be converted to a pointer to a different object or incomplete type. If the resulting pointer is not correctly aligned57) for the pointed-to type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer.

в сочетании с "All pointers to structure types shall have the same representation and alignment requirements as each other." никакого UB в примере ТС нет. Равно как и "условие внутри if() никогда не выполнится". Чтобы компилятор в этом случае не ругался, вполне законным считается использование промежуточного приведения к (void *).

SilentBob ()

[C] Преобразование указателей на структуры

>У трёх структур общее "начало". Указатели на экземпляры структур s1 и s2 преобразовываются к указателям s_base. Гарантируется ли стандартом Си, что условие внутри if() никогда не выполнится?

Варианты в Си делаются через union.

union vals_t { double d; float f; integer i; ...whatever.. };

struct variant_t { int tag union vals_t vals; };

Absurd ★★★ ()

[C] Преобразование указателей на структуры

так надежней всего :)

struct s_base
{
int tag;
};

struct s1
{
struct s_base base;
int data;
};

struct s2
{
struct s_base base;
float data;
};

xydo ★★ ()

Re: [C] Преобразование указателей на структуры

ну, не я первым начал извращение))
к тому же это куда красивее, чем:
struct s1 a;struct s_base *b = (struct s_base *) &a;
и потом, когда тебе понадобится что-то добавить в s_base, настанет большой песец.

хотите красивый код в данном случае - используйте С++

xydo ★★ ()

Re: [C] Преобразование указателей на структуры

>хотите красивый код в данном случае - используйте С++

О да. Я даже знаю одну типобезопасную реализацию union-ов. Некоторым даже удалось ее скомпилировать. http://www.oonumerics.org/tmpw01/alexandrescu.pdf

Absurd ★★★ ()

[C] Преобразование указателей на структуры

в питоне тоже самое

gavv ()

[C] Преобразование указателей на структуры

#define STRUCT_DEF struct s_base \
{ \
int tag; \
}; \
struct s1 \
{ \
struct s_base base; \
int data; \
}; \
struct s2 \
{ \
struct s_base base; \
float data; \
};  \

#define GET_TAG(a) a.base.tag;

#define MAIN_F int main() \
{ \
    struct s2_obj; \
    GET_TAG(s2_obj) = new_tag; \
    return 0; \
} \

STRUCT_DEF
MAIN_F

так штоле?

g ()

[C] Преобразование указателей на структуры

А что нельзя через наследование все сделать. Есть базовая структура struct s_base, есть две структуры-потомки (struct s1 и struct s2) поле type в структуре предке. Компилятор тогда всё гарантирует.

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