未命名结构的前向声明

Forward declarations of unnamed struct

本文关键字:声明 结构 未命名      更新时间:2023-10-16

赏金问题:所以,这两个Foo不是一回事。很好。第二种形式是在图书馆给出的。如果我不能更改它,我如何向前声明它?


我一直认为C和c++允许重复声明,只要没有重复的定义。然后我在尝试编写扩展C库的c++代码时遇到了这个问题。

struct Foo;
typedef struct {} Foo;

这会产生以下错误:

'struct Foo'前面有一个声明为'struct Foo'

我想向前声明,该死!这是怎么了?

类型定义匿名结构是c++ 03之前的一种实践,主要是为了保持与c99之前的编译器的兼容性。

考虑到这是2011年,c++和C都改变了,我想知道为什么没有这样一个库的最新版本!

如果它不再处于发展中,你不能"离开",只能"生存",改变它是做到这一点的方法。如果仍在部署中,请将问题提交给开发团队。

如果需要变通,考虑该结构可以继承。因此,写一个像

这样的前向声明
struct MyFoo;

并定义为

#include "old_library.h"
struct MyFoo: public Foo {};

在你所有的代码中,忘记Foo而总是使用MyFoo .

你声明了两个具有相同名称的不同实体。第一个是struct Foo,是一个名为Foo的结构体。第二个是匿名结构的别名。

如果你这样做:

struct Foo;
struct Foo {};

它可以工作,因为在这两种情况下你都声明了一个名为Foo的结构体。

不能转发声明匿名结构。您有两种选择:包括整个定义,或者更改头文件并命名结构体。

在类似的情况下,我有一个类似

的旧C头文件
== old_library.h ==
typedef struct { int data; } Foo;
== /old_library.h ==

我在自己的c++类中使用它,作为私有方法的参数:

class C {
  void run(Foo *ds);
  ...
}

为了避免C.hpp中的#include "old_library.h",我使用了以下前向声明:

class C {
  struct Foo;
  void run(Foo *ds);
  ...
}

和C.cpp中有以下语句:

extern "C" {
#include "old_library.h"
}
struct C::Foo : public ::Foo {};

这样,我透明地使用C::Foo而不是Foo,并且不需要MyFoo!

你不需要在c++中定义类型:

struct Foo;     // Forward declaration
struct Foo 
{
}; // Definition

如果您想在C中只调用Foo而不是struct Foo,则需要类型定义,这也可以通过不同的方式完成:

struct Foo;     /* Forward declaration */
struct Foo /* The name is needed here */
{
}; /* Definition */
typedef struct Foo Foo;  /* typedef */

struct Foo;     /* Forward declaration */
typedef struct Foo /* The name is needed here */
{
} Foo; /* Definition and typedef combined */

当然可以在C和c++中使用struct Foo的形式。

您的forward声明声明将有一个struct称为Foo

第二个声明是typedef,称为Foo。这不是一回事。

对于类型定义的前向声明,您需要引用正在被类型定义的内容,例如:

struct foo;
typedef foo bar;
class foo{};

因为你想要前向声明一个匿名结构,你既不能在原始实体的前向声明中给它一个名字,也不能在对它进行类型定义时引用它。"逻辑"语法应该是:

struct ;
typedef bar;
class {};

但是由于这显然是不可能的,所以你不能向前声明匿名结构。

让我们看一下9.1-2:

仅由类键标识符组成的声明;要么是在当前作用域或forward中重新声明名称将标识符声明为类名。它介绍了这个类

没有标识符,没有前向声明。

底线:避免匿名结构,除非它们给你真正需要的优势。

您的特定编译器在这里可能会有所不同。

使用MinGW GCC 3.4.5,两个声明编译时没有错误或警告(使用-Wall)

struct Foo;
typedef struct {} Foo;

struct Foo;
typedef struct Foo {} Foo;

是否可能在库中已经存在前向声明?例如,要允许一个循环指针:

struct Foo;
typedef struct Foo {
    struct Foo *fooPtr;
} Foo;

如果这已经存在于库头文件中,它将导致您所描述的错误。

IMHO,只需将typedef更改为,

typedef struct Foo {} Foo;
              ^^^^^

这是没有害处的,它仍然在C &c++。现在你可以向前声明了。

[注:如果你仍然坚持不碰typedef,那么这里是肮脏的技巧

struct Foo;
#define struct struct Foo
#include"Foo.h"  // contains typedef struct {} Foo;
#undef struct

这将工作,只有当Foo.h只包含一个struct声明。我不推荐使用

我想我最近遇到了与原来海报相同的问题,并已解决如下:

我正在编写一个围绕第三方提供的API的包装器,定义为:

foo:

typedef struct _foo 
{
    int i;
} Foo;
Foo* MakeFoo();
int UseFoo(Foo* foo);

我的包装器需要将Foo作为成员,但我不想将Foo暴露给包装器的所有消费者。

UberFoo.h:

#pragma once
struct _foo;  // forward declare the actual type _foo, not the typedef Foo
class UberFoo
{
public:
    UberFoo();
    int GetAnswer();
private:
    _foo* f;
};

UberFoo.cpp:

#include "UberFoo.h"
#include "Foo.h"
UberFoo::UberFoo()
{
    this->f = MakeFoo();
}
int UberFoo::GetAnswer()
{
    return UseFoo(f);
}

现在,我的类的消费者可以实例化它,而不必访问_foo/Foo的实际定义。如果我需要将指针作为参数传递给_foo或从函数返回指针,以及拥有成员_foo,这也可以工作。

main.cpp:

#include <cstdio>
#include "UberFoo.h"
int main(int argc, char* argv[])
{
    UberFoo u;
    printf( "The Answer = %dn", u.GetAnswer());
    return 0;
}
这里的技巧是转发声明实际的结构类型,而不是类型定义的名称。请注意,结构体不能是匿名的,这一点很重要,因为在旧的C代码中很常见:
typedef struct // the actual struct type underlying the typedef is anonymous here
{
    int i;
} ThisWontWork;

希望这对你有帮助!

你不能向前声明它,因为它是未命名的。它是一个未命名的结构体,Foo是一个类型定义。

为什么不直接避免转发呢?

如果第二个定义在头文件中,可以首先在c++头文件中包含这个头文件。为了使c++将其视为C头文件,在大多数情况下,在extern "C" {}中包含#include就足够了。

您正在尝试定义以前使用过的名称。该语句完全有效,只是需要使用不同的名称。

struct Foo; // Forward declaration of struct Foo
typedef struct {} anotherFoo; // Another structure typedefed
struct Foo {
 // Variables
}; // Definition of the forward declared Foo.