gpt4 book ai didi

转换结构指针

转载 作者:太空狗 更新时间:2023-10-29 15:58:17 25 4
gpt4 key购买 nike

假设代码使用 c11 编译并启用严格别名。

我不是在寻找不同的方法,我想专注于这个特定问题,以及它是否有效或为什么无效。

(如果我无意中犯了一些不相关的错误,请告诉我,我会修复)

c11 标准说:

6.2.5.28 All pointers to structure types shall have the same representation and alignment requirements as each other.

6.7.2.1.6 a structure is a type consisting of a sequence of members, whose storage is allocated in an ordered sequence

这意味着结构 A 和 B 中指针的大小和对齐方式相同。

#include <stdio.h>
#include <stdlib.h>

struct S1
{
int i ;
} ;

struct S2
{
float f ;
} ;

struct A
{
struct S1* p ;
} ;


struct B
{
struct S2* p ;
} ;


int main( void )
{

结构 A 和 B 有指向结构 S1 和 S2 的指针,结构 A 和 B 保证具有相同的大小和对齐方式。

我们有一个 struct B,它的成员指针是一个 struct S2 指针,但指向某个 struct S1,这是通过 void* 转换实现的。

struct S1 s1 = { 0 } ;

struct B* b = malloc( sizeof( *b ) ) ;
b->p = ( void* ) &s1 ;

没关系,我们可以存储指针,只要我们不实际使用指针即可。但我们想要。我们可以将指针转换为结构 S1。

( ( struct S1* )(b->p) )->i = 123 ;    //redundant brackets for emphasis

printf("%d\n" , s1.i ) ;

并正确使用它。

到目前为止,我没有发现任何问题,因为指针已转换为正确的类型。

但是我们可以将整个结构 B 转换为结构 A 吗?它们在大小和对齐方面是相同的,尽管标准可能会提示(?),编译器会产生未定义的行为吗?

( ( struct A* )b)->p->i = 666 ;

printf("%d\n" , s1.i ) ;

我知道解决方案是使用 union (或使用 void 并随时正确转换),因为标准允许使用上次未使用的成员来存储值。

6.5.2.3.3( 95 ) If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called "type punning"). This might be a trap representation.

但是,我想避免这种情况:

struct C
{
union
{
struct S1* p1 ;
struct S2* p2 ;
} ;
} ;

struct C* c = malloc( sizeof( *c ) ) ;

c->p2 = ( void* )&s1 ;

c->p1->i = 444 ;

printf("%d\n" , s1.i ) ;

return 0 ;
}

Above code without text .

最佳答案

到目前为止您所描述的内容:

But can we cast the whole struct B to struct A instead?

都是正确的,但不幸的是这个问题的答案是 如果两个结构包含“公共(public)初始序列”,则只允许通过指向不兼容类型的指针访问结构,一世。 e.如果他们的前几个成员具有相同的类型。由于您的结构没有(即,第一个成员属于不同类型),因此通过指向 S2 的指针访问 S1 类型的对象是不合法的,反之亦然反之亦然。特别是,这样做违反了 strict aliasing rule .

来自 C99,6.5.7:

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:76)

— 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.

关于转换结构指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21650839/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com