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

发布于 2024-12-11 20:20:44 字数 741 浏览 0 评论 0原文

这是此问题的后续问题。

我试图避免使用显式 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: incomplete types in assignment< /code>,但是使用 Open Watcom 可以很好地编译(并且按我的预期工作,打印 1 到 3)。

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

编辑:我很清楚这是一种糟糕的编码风格。问题是关于另一件事。我很好奇海湾合作委员会的行为背后是否有逻辑依据,是否合法。

This is a follow-up to this question.

I'm trying to avoid using an explicit typedef to copy one array to another through casts like this:

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

With gcc I'm getting arrcpy.c:8: error: incompatible types in assignment, however with Open Watcom it compiles fine (and works as I expect it, printing 1 through 3).

Is the gcc's behavior per the standard or not? If it is, what's the relevant chapter and section? I can't understand why two identical type definitions struct{int _[3];} aren't the same (or compatible) in the gcc's eyes.

EDIT: I know full well it's a bad coding style. The question is about a different thing. I'm curious if there's a logical rationale behind the gcc's behavior, if it's legit.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

写下不归期 2024-12-18 20:20:45

为什么不直接使用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的答案,编译器看到两个结构定义就是两种不同类型的结构。尽管它们可能包含相同的数据,但它们是两种不同的类型。

Why wouldn't you just use 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;
}

or for the size, instead of 3: sizeof(dst)/sizeof(dst[0])

EDIT: With your edit, I can only assume that, as with outis' answer, the compiler sees the two struct definitions as just that, two different types of structs. Even though they may contain the same data, they're two different types.

何必那么矫情 2024-12-18 20:20:45

基本上,类型等价不是 C 中的结构等价。 C 使用 主格类型系统

根据 C99 § 6.7.2.1-7:

结构或联合说明符中结构声明列表的存在声明了翻译单元内的新类型。 struct-declaration-list 是结构或联合成员的声明序列。如果结构声明列表不包含命名成员,则行为未定义。在终止列表的 } 之前,类型是不完整的。

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

struct-or-union-specifier:
    结构或联合标识符opt { struct-declaration-list }

结构或联合:
    结构
    联盟

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

如果要避免污染全局命名空间,可以在使用该结构的函数中本地声明该结构。

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

Basically, type equivalence isn't structural equivalence in C. C uses a nominative type system.

According to § 6.7.2.1-7 of C99:

The presence of a struct-declaration-list in a struct-or-union-specifier declares a new type, within a translation unit. The struct-declaration-list is a sequence of declarations for the members of the structure or union. If the struct-declaration-list contains no named members, the behavior is undefined. The type is incomplete until after the } that terminates the list.

struct-declaration-list and struct-or-union-specifier come from the C grammar (§ 6.7.2.1):

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

struct-or-union:
    struct
    union

Even if two different structs have the same memory layout, they are different types.

If you want to avoid polluting the global namespace, you can declare the struct locally to the function in which you use it.

#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;
}
姜生凉生 2024-12-18 20:20:44

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

The gcc behavior is right, the types are two unrelated unnamed structures. Each of those structs, while having the same memory layout, have different names. If you really want to do that, then use a typedef.

澜川若宁 2024-12-18 20:20:44

这两个 struct 定义不兼容:

从 C99 6.2.7 开始:

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

类型不相同。然而,如果它们在单独的翻译单元中声明,它们将是兼容的。

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

  1. 它使用保留的名称“_”。
  2. 不允许以不同类型访问对象(通过 char 指针、联合等的结构除外)。

The two struct definitions are not compatible:

From C99 6.2.7:

Two types have compatible type if their types are the same. Additional
rules for determining whether two types are compatible are described
in 6.7.2 for type specifiers, in 6.7.3 for type qualifiers, and in
6.7.5 for declarators. Moreover, two structure, union, or enumerated types declared in separate translation units are compatible
if their tags and members satisfy the following requirements...

The types aren't the same. If they were declared in separate translation units, they would be compatible, however.

However, even if they were compatible, your code would still invoke undefined behavior, for at least two reasons:

  1. It uses the name "_" which is reserved.
  2. Accessing objects as a different type (except structs through char pointers, unions, etc.) isn't allowed.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文