2012-01-02 44 views
7

假设我们有两种结构:结构指针兼容性

typedef struct Struct1 
{ 
    short a_short; 
    int id; 
} Struct1; 

typedef struct Struct2 
{ 
    short a_short; 
    int id; 
    short another_short; 
} Struct2; 

是否安全,从Struct2 *转换为Struct1 *? ANSI规范对此有何评论? 我知道一些编译器可以选择对结构字段进行重新排序来优化内存使用,这可能会导致两个结构不兼容。无论编译器标志如何,是否有任何方法可以确保此代码有效?

谢谢!

+2

*重新排序*成员不被标准AFAIK允许。我相信插入不同数量的填充是允许的。 – delnan 2012-01-02 15:53:40

+0

@delnan哦,那么结构'包装'只会禁用对齐?谢谢,我不知道! – Waneck 2012-01-02 16:00:23

回答

5

结构指针类型总是有在C.相同的表示

(C99,6.2.5p27)“所有指针结构类型应具有相同的 表示和对准要求彼此”。

而在结构类型成员总是为了在C.

(C99,6.7.2.1p5)“的结构是一类由 成员的序列的,其存储被分配以有序序列“

+1

这不回答这个问题;即使有这些限制,它仍然可能是一个别名违规。但是,在某些情况下,C标准确实明确允许OP需要什么。 – 2012-01-02 15:57:40

+0

非常感谢您从ANSI规范中引用这些引用。这对我来说很清楚,这是安全的! – Waneck 2012-01-02 15:58:40

+0

@ R。什么条件? – Waneck 2012-01-02 15:59:20

2

它很可能会工作。但是,您在询问如何确保此代码有效时非常正确。所以:在你的程序的某个地方(在启动时也许)嵌入了一堆ASSERT语句,这些语句确保offsetof(Struct1.a_short)等于offsetof(Struct2.a_short)等。另外,除了你以外的某个程序员可能有一天会修改其中一个结构,但不是另一个,所以更好安全比对不起。

+0

使用静态断言会好得多...... – 2012-01-02 15:58:19

+0

感谢Mike,我肯定会添加一些断言来确保这一点! – Waneck 2012-01-02 16:03:52

+0

@R ..静态断言?我不知道他们存在。[我查了一下,发现](http://stackoverflow.com/questions/3385515/static-assert-in-c)。你是对的,谢谢。 – 2012-01-02 16:10:29

3

就我所知,它是安全的。

但它好得多,如果可能的话,要做到:

typedef struct { 
    Struct1 struct1; 
    short another_short; 
} Struct2; 

然后,你甚至告诉编译器Struct2开始与Struct1一个实例,因为一个指向结构总是在指出其第一个成员,您可以安全地将Struct2 *视为Struct1 *

+0

好吧,如果有一天偶然会有'offsetof(Struct1.a_short)'被找到不等于'offsetof(Struct2.a_short)',那么存在相等数量的机会,一天'offsetof(Struct2.struct1)'将被发现不等于零。 (这意味着'&struct2!=(Struct2 *)&struct2.struct1')。 – 2012-01-02 15:56:00

+0

确实,这种方式好多了! :) 谢谢! – Waneck 2012-01-02 15:56:24

+0

如果struct1和struct2都将“int”放在第一位并且“int”需要32位对齐,那么这两种结构类型都可以是8个字节,但是您的另一种形式的Struct2需要12个字节。如果编译器遵守Common Initial Sequence规则,那么任何一种形式都应该是有效的(8字节形式会更有效),但即使在C89模式下调用,gcc不再支持C89的保证,除非'-fno-strict-别名“标志被使用。 – supercat 2017-04-12 22:17:39

1

是的,可以这么做!

示例程序如下。

#include <stdio.h> 

typedef struct Struct1 
{ 
    short a_short; 
    int id; 
} Struct1; 

typedef struct Struct2 
{ 
    short a_short; 
    int id; 
    short another_short; 
} Struct2; 

int main(void) 
{ 

    Struct2 s2 = {1, 2, 3}; 
    Struct1 *ptr = &s2; 
    void *vp = &s2; 
    Struct1 *s1ptr = (Struct1 *)vp; 

    printf("%d, %d \n", ptr->a_short, ptr->id); 
    printf("%d, %d \n", s1ptr->a_short, s1ptr->id); 

    return 0; 
}