C 强制转换结构指针

C 强制转换结构指针,c,pointers,struct,c11,C,Pointers,Struct,C11,假设代码是使用c11编译的,并且启用了严格别名 我不是在寻找一种不同的方法,我想专注于这个特定的问题,以及它是否有效或者为什么无效 (如果我无意中犯了一些不相关的错误,请让我知道,我会纠正它) c11标准规定: A pointer to a structure object, suitably cast, points to its initial member (or if that member is a bit-field, then to the unit in which it res

假设代码是使用c11编译的,并且启用了严格别名

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

(如果我无意中犯了一些不相关的错误,请让我知道,我会纠正它)

c11标准规定:

A pointer to a structure object, suitably
cast, 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
therefore be unnamed holes within a structure object, but not at its
beginning, as necessary to achieve the appropriate alignment.
6.2.5.28 指向结构类型的所有指针应具有彼此相同的表示和对齐要求

6.7.2.1.6 结构是由一系列成员组成的类型,其 存储是按顺序分配的

这意味着结构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 )
{
没关系,我们可以存储指针,只要我们不实际使用指针。 但是我们想。 我们可以将指针强制转换为结构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 ) ;
我知道解决方案是使用一个联合(或者使用一个空白,并在任何时候正确地进行转换),因为标准允许使用成员(不是最后一次用于存储值)

6.5.2.3.3(95) 如果用于读取联合对象内容的成员与上次用于在对象中存储值的成员不同,则该值的对象表示的适当部分将重新解释为6.2.6中所述的新类型中的对象表示(有时称为“类型双关”的过程)。这可能是一个陷阱表示

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

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 ;
}

.

我认为在这种特殊情况下,您的示例将起作用,并且符合标准。ANSI标准规定:

A pointer to a structure object, suitably
cast, 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
therefore be unnamed holes within a structure object, but not at its
beginning, as necessary to achieve the appropriate alignment.
示例中的指针
p
始终是结构的第一个(也是唯一的)字段。在我对前一段的理解中,指向<代码>结构的指针与指针“<代码:>::p/COD>(对不起,C++符号)相同,它与指向代码< B::P< <代码>的指针相同,它与指针<代码> B<代码>相同。显式转换不会更改指针的值,因此您的示例应符合标准


说它不是很漂亮也没用,你的老板可能不会欣赏这种编程风格。

直到现在你所描述的:

但是我们可以将整个结构B转换为结构A吗

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

从C99,6.5.7:

对象的存储值只能由具有以下类型之一的左值表达式访问:76)

-与对象的有效类型兼容的类型

-与对象的有效类型兼容的类型的限定版本

-与对象的有效类型相对应的有符号或无符号类型

-一种类型,它是与对象的有效类型的限定版本相对应的有符号或无符号类型

-在其成员中包含上述类型之一的聚合或联合类型(递归地包括子聚合或包含的联合的成员),或

-字符类型


在表达式
((struct A*)b)->p->i
中,对
p
的访问违反了C 2011 6.5 7,其中规定“对象的存储值只能由具有以下类型之一的左值表达式访问:与对象的有效类型兼容的类型,…”
b->p
是指向结构S2的指针,但
((结构a*)b)->p
是一个左值表达式,其类型指针指向结构S1。尽管这些指针的表示形式可能相同,但它们是不兼容的类型。

“结构A和B保证具有相同的大小”-我认为这不能保证。。。(尽管我承认这在实践中很有可能…@OliCharlesworth我不认为他们什么时候会有所不同。非常具体的情况或系统?可能是超出范围的问题。你有没有暗示你想如何使用这个魔法?您只是想将float的一部分修改为int吗?如果是的话,你肯定可以做得更容易。我真的看不出有任何兴趣做那些结构转换。@Marian你有什么建议要如何使用这个魔法吗?对您只是想将float的一部分修改为int吗?我想知道如何正确访问结构(在问题中详细阐述)。我真的看不出有任何兴趣做那些结构转换。这是一个sscce。这意味着这只是我整个代码库的一个最小示例,目前需要这些转换。指针b->p和a->p是不同的,它们分别是指向S1和S2类型的指针。它们在铸造时是一样的,但这就是问题所在,在c语言中,有时你不能这么做。@self。如果将
a*
类型的
a
b*
类型的
b
指针取为a==b,则表达式
a->p
给出的值与
((b*)a)->p
b->p
((a*)b)->p
相同。这不是你问题的核心吗?你的意思是:a->p==((B)a)->p==B->p==((a*)B)->p*?如果
a==b
,则
a->p
b->p
的指针类型不同。因为他们解释da