Приведение указателя структуры к типу, который лежит первым полем в структуре
Допустим, у меня есть некая структура, так называемая структура для подсчета ссылок:
#ifndef LIBKODIK_API_OBJECT_BASE
# define LIBKODIK_API_OBJECT_BASE \
uint32_t i_refs_count; \
struct libkodik_api_object_t *p_parent \
#endif /* !LIBKODIK_API_OBJECT_BASE */
typedef struct libkodik_api_object_t {
LIBKODIK_API_OBJECT_BASE;
} libkodik_api_object_t;
uint32_t
libkodik_api_object_retain(libkodik_api_object_t *p_object);
uint32_t
libkodik_api_object_release(libkodik_api_object_t *p_object);
uint32_t
libkodik_api_object_retain(libkodik_api_object_t *p_object) {
libkodik_api_object_t *p_current = p_object;
while (NULL != p_current) {
p_current->i_refs_count++;
p_current = p_current->p_parent;
}
return p_object->i_refs_count;
}
uint32_t
libkodik_api_object_release(libkodik_api_object_t *p_object) {
libkodik_api_object_t *p_current = p_object;
while (NULL != p_current) {
p_current->i_refs_count--;
p_current = p_current->p_parent;
}
return p_object->i_refs_count;
}
И есть другая структура, в которой первым полем лежит libkodik_api_object_t:
struct kodik_api_countries_t {
libkodik_api_object_t s_api_base;
...
};
Могу ли я безопасно вызывать libkodik_api_object_retain, libkodik_api_object_release делая простой каст указателя на другой тип струкруты?
libkodik_api_object_retain((libkodik_api_object_t *) p_countries_api);
libkodik_api_object_release((libkodik_api_object_t *) p_countries_api);
P.S. libkodik_api_object_release не освобождает память, а просто уменьшает кол-во ссылок на 1.
Ответы (1 шт):
Да, согласно стандарту† (§ 6.5 / 7)
(7) An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
- a type compatible with the effective type of the object,
- a qualified version of a type compatible with the effective type of the object,
- a type that is the signed or unsigned type corresponding to the effective type of the object,
- a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
- an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
- a character type.
А также (§ 6.7.2.1 / 15)
(15) Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning.
Другими словами, указатель на структуру может быть приведен к указателю на первый элемент этой структуры и это не будет являться нарушением strict aliasing rule:
#include <stdio.h>
struct A {
int value;
};
struct B {
struct A a;
};
void print_value(struct A *);
int
main(void)
{
struct B b = {{42}};
print_value((struct A *) &b);
}
void
print_value(struct A *a)
{
printf("%d\n", a->value);
}
† ISO/IEC 9899:2011 (E).