转换/赋值中不兼容的结构类型?

时间:2011-10-25 00:33:13

标签: c struct

这是this question的后续行动。

我试图避免使用显式的 typedef 通过这样的强制转换将一个数组复制到另一个数组:

#include <stdio.h>

int main(void)
{
  int i;
  int dst[] = { 10, 20, 30 }, src[] = { 1, 2, 3 };

  *(struct{int _[3];}*)dst = *(struct{int _[3];}*)src;

  for (i = 0; i < 3; i++) printf("%d\n", dst[i]);
  return 0;
}

使用gcc,我得到arrcpy.c:8: error: incompatible types in assignment,但是使用Open Watcom,它编译得很好(并按照我的预期工作,打印1到3)。

gcc的行为是否符合标准?如果是,那么相关的章节是什么?我无法理解为什么两个相同的类型定义struct{int _[3];}在gcc眼中不一样(或兼容)。

编辑:我完全知道这是一种糟糕的编码风格。问题是关于另一件事。我很好奇gcc的行为背后是否有合理的理由,如果它是合法的。

4 个答案:

答案 0 :(得分:6)

gcc行为是正确的,类型是两个不相关的未命名结构。每个结构虽然具有相同的内存布局,但具有不同的名称。如果你真的想这样做,那就使用typedef。

答案 1 :(得分:1)

为什么不使用memcpy

#include <stdio.h>
#include <string.h>

int main(void)
{
  int i;
  int dst[] = { 10, 20, 30 }, src[] = { 1, 2, 3 };

  memcpy(dst, src, 3 * sizeof(int));

  for (i = 0; i < 3; i++) printf("%d\n", dst[i]);
  return 0;
}

或尺寸,而不是3:sizeof(dst)/sizeof(dst[0])

编辑:通过编辑,我只能假设,与outis' answer一样,编译器将两个结构定义看作是两种不同类型的结构。尽管它们可能包含相同的数据,但它们有两种不同的类型。

答案 2 :(得分:1)

基本上,C中的类型等价不是structural等价.C使用nominative type system

根据C99的第6.7.2.1-7段:

  

struct-or-union-specifier中struct-declaration-list的存在在转换单元中声明了一个新类型。 struct-declaration-list是结构或联合成员的一系列声明。如果struct-declaration-list不包含命名成员,则行为未定义。在终止列表的}之前,类型是不完整的。

struct-declaration-liststruct-or-union-specifier来自C语法(第6.7.2.1节):

struct-or-union-specifier:
    struct-or-union identifieropt { struct-declaration-list }

struct-or-union:
    struct
    union

即使两个不同的结构具有相同的内存布局,它们也是不同的类型。

如果您想避免污染全局命名空间,可以在本地将结构声明为您使用它的函数。

#include <stdio.h>

int main(void) {
    // struct T is only visible in main()
    struct T {int _[3];};
    int i;
    int dst[] = { 10, 20, 30 }, src[] = { 1, 2, 3 };

    *(struct T*)dst = *(struct T*)src;

    for (i = 0; i < 3; i++) printf("%d\n", dst[i]);

    return 0;
}

void fails(void) {
    // will cause a compilation error, because struct T is an incomplete type.
    struct T t;
}

答案 3 :(得分:1)

两个struct定义不兼容:

来自C99 6.2.7:

  

如果类型相同,则两种类型具有兼容类型。额外   描述了用于确定两种类型是否兼容的规则   6.7.2中的类型说明符,6.7.3中的类型限定符,以及   6.7.5为声明者。此外,在单独的翻译单元中声明的两个结构,联合或枚举类型是兼容的   如果他们的标签和成员满足以下要求......

类型不一样。如果它们是在单独的翻译单元中声明的,那么它们将是兼容的。

但是,即使它们兼容,您的代码仍会调用未定义的行为,至少有两个原因:

  1. 使用名称“_”保留。
  2. 不允许以不同的方式访问对象(通过字符串指针,联合等除了结构)。