繁体   English   中英

typedef 的重新定义

[英]redefinition of typedef

我有一个大型 C 应用程序,我试图遵循不包含其他头文件中的头文件的风格。 相反,使用前向声明; 因此我正在尝试以下操作。

// in A.h
typedef struct A_ A;
typedef struct B_ B;
struct A_ {
    double a;
    B *b;
};

// in B.h
typedef struct B_ B;
struct B_ {
    int c;
};

// in C.h
typedef struct A_ A;
typedef struct B_ B;
void function_do_something(A*, B*);

// in C.c
#include "A.h"
#include "B.h"
#include "C.h"
void function_do_something(A* a, B* b) {
    ...
}

这个范例在 Ubuntu 11.10 gcc 中编译和运行——但它在 OpenSUSE gcc 中给出了编译器错误,说“重新定义 typedef”。

我一直在 Ubunutu 中进行开发,所以没有意识到这种范式可能是不正确的。 仅仅是因为这是完全错误的并且 Ubuntu 的 gcc 太好了吗?

我对此感到惊讶,因为我相当确定在同一范围内重新声明相同的 typedef 在 C++ 中是合法的,但显然在 2011 标准之前在 C 中是不合法的。

首先,typedef 名称没有链接:

ISO/IEC 9899:1999 + TC3 6.2.6/6:

以下标识符没有链接:声明为对象或函数以外的任何标识符的标识符 [...]

和 6.7/3:

如果标识符没有链接,除了 6.7.2.3 中规定的标签外,在相同的范围和相同的名称空间中,标识符的声明(在声明符或类型说明符中)不得超过一个。

因此,您需要确保每个 typedef 声明在每个翻译单元的文件范围内仅出现一次。

2011 C 标准允许重新声明 typedef 名称。 6.7 3 说:

... typedef 名称可以重新定义以表示与当前相同的类型,前提是该类型不是可变修改的类型;...

缺少一个成语。 前向声明独立于定义,因此它们应位于单独的头文件中。

// a_fwd.h

#ifndef A_FWD_H
#define A_FWD_H

typedef struct A_ A;

#endif

// a.h

#ifndef A_H
#define A_H

#include "a_fwd.h"

struct A_ {
};

#endif

现在以任何顺序包含任何标题总是安全的。


对任何事物有两个定义是违法的。 typedef 是一个定义,而不仅仅是一个声明,因此一个编译器非常松懈以允许冗余。

就风格而言,我会将 typedef 放在结构之后。 IE:

struct B_ {
    int c;
};
typedef struct B_ B;

这样你就会说:“这里是 B_,现在我想把它称为 B”。 可能是相反的方式愚弄了编译器中的某些东西。

ubuntu 编译器过于软; 你不能两次 typedef 相同的东西。 在您引用的样式中,包含的顺序很重要,通常在头文件或文档中作为注释提及。 在这种情况下,您将拥有:

//A.h
typedef struct A A;
struct A {
    double a;
    B* b;
};

// B.h
typedef struct B B;
struct B {
    int c;
};

// C.h
void function_do_something(A*, B*);

// C.c
#include "B.h"
#include "A.h"
#include "C.h"

void function_do_something(A* a, B* b){ ... }

您可能会注意到,在循环依赖的情况下,这会变得混乱。

您通过在多个头文件中编写相同的语句来重新定义 A 和 B。 一种解决方案是从 Ah 和 Bh 中删除 A 和 B 的typedef并按原样使用您的 Ch。

正如其他人已经说过的,你不能在 C 中重新定义类型。这个错误主要表明可能存在循环包含或其他逻辑缺陷。 为避免这种情况,最佳做法是锁定包含文件,即

#ifndef __HEADER_H__
#define __HEADER_H__

// Your code goes here

#endif

这样不必要的包含将被这个锁省略。
在您的示例中,您需要在 A 中包含 B,在 C 中包含 A。在 C 中包含 B 没有任何效果,并且会满足编译器的要求

您多次定义同一件事。

您可以将它分布在多个头文件中,只需确保在定义 struct _A 之前看到了一些 B。

此代码有效:

#include <stdio.h>

typedef struct _B B;
typedef struct _A A;

struct _A {
    double a;
    B *b;
};

struct _B {
    int c;
};

void function_do_something(A* a, B* b)
{
    printf("a->a (%f) b->c (%d)\n", a->a, b->c);
}

int main()
{
   A a;
   B b;

  a.a = 3.4;
  b.c = 34;

  function_do_something(&a, &b);

  return 0;
}

输出:

> ./x
a->a (3.400000) b->c (34)

编辑:更新为 C

编辑2 :传播到多个头文件

哈:

#ifndef B_H
#define B_H

struct _B {
    int c;
};

#endif

啊:

#ifndef A_H
#define A_H

typedef struct _B B;

struct _A {
    double a;
    B *b;
};

typedef struct _A A;

#endif

主文件:

#include <stdio.h>

#include "a.h"
#include "b.h"

void function_do_something(A* a, B* b)
{
    printf("a->a (%f) b->c (%d)\n", a->a, b->c);
}

int main()
{
   A a;
   B b;

  a.a = 3.4;
  b.c = 34; 

  function_do_something(&a, &b);

  return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM