【问题标题】:forward declaration of a struct in C?C中结构的前向声明?
【发布时间】:2012-04-03 18:50:57
【问题描述】:
#include <stdio.h>

struct context;

struct funcptrs{
  void (*func0)(context *ctx);
  void (*func1)(void);
};

struct context{
    funcptrs fps;
}; 

void func1 (void) { printf( "1\n" ); }
void func0 (context *ctx) { printf( "0\n" ); }

void getContext(context *con){
    con=?; // please fill this with a dummy example so that I can get this working. Thanks.
}

int main(int argc, char *argv[]){
 funcptrs funcs = { func0, func1 };
   context *c;
   getContext(c);
   c->fps.func0(c);
   getchar();
   return 0;
}

我在这里遗漏了一些东西。请帮我解决这个问题。谢谢。

【问题讨论】:

  • C 不允许你只说context *whatever;,是吗?我想这肯定让你说struct context *whatever;...

标签: c struct declaration forward-declaration


【解决方案1】:

结构体(没有 typedef)在使用时通常需要(或应该)与关键字 struct 一起使用。

struct A;                      // forward declaration
void function( struct A *a );  // using the 'incomplete' type only as pointer

如果你 typedef 你的结构,你可以省略 struct 关键字。

typedef struct A A;          // forward declaration *and* typedef
void function( A *a );

注意重复使用结构名是合法的

尝试在您的代码中将前向声明更改为此:

typedef struct context context;

添加后缀来指示结构名称和类型名称可能更具可读性:

typedef struct context_s context_t;

【讨论】:

  • 不错!我使用您提到的最后一种方法,略有不同: typedef struct context_s context;当你知道你永远不会使用令牌“context_s”但会使用“context”时,这很好。
【解决方案2】:

试试这个

#include <stdio.h>

struct context;

struct funcptrs{
  void (*func0)(struct context *ctx);
  void (*func1)(void);
};

struct context{
    struct funcptrs fps;
}; 

void func1 (void) { printf( "1\n" ); }
void func0 (struct context *ctx) { printf( "0\n" ); }

void getContext(struct context *con){
    con->fps.func0 = func0;  
    con->fps.func1 = func1;  
}

int main(int argc, char *argv[]){
 struct context c;
   c.fps.func0 = func0;
   c.fps.func1 = func1;
   getContext(&c);
   c.fps.func0(&c);
   getchar();
   return 0;
}

【讨论】:

  • 只说 OP 代码中必须更改的内容会更清楚。
【解决方案3】:
#include <stdio.h>
struct b; // not needed because:
struct a {
    struct b * pb;  //this member definition also forward declares struct b
    int c;
};

typedef struct a a // needed for a but not struct a because:
struct b {
    struct a* pa;     //this member definition also forward declares struct a
    a * pa1;
    void * c;
};

int main() {
    printf("Hello, world!");
    return 0;
}

基本上,您永远不需要单独转发声明struct b,因为当您使用它执行纯声明时,它总是在行本身上声明部分类型,因此这是冗余代码。这种前向声明的唯一好处是它可以与 typedef 一起使用。在 C++ 中,您不需要 typedef,因为 struct 和 typedefs 在同一个标​​识符命名空间中,因此 struct b 变得有用,因为它现在声明了 b,因此您将在 C++ 中看到它。

关键是如果在你使用它来声明实际上是暂定定义而不是声明的东西之前该类型没有完成(所以struct e f在文件/块范围内没有extern)不是一个指针,或者如果你试图取消引用指针,如果它是一个指针,那么你会得到一个不完整的类型错误。

所以它更像是允许您使用不完整的类型。忘记前向声明,因为这不是单独的操作。它是struct g* h 行的一部分。您永远不需要使用其他东西实际需要的前向声明(除非它是 typedef),因为它在自己的行中有前向声明部分。

能够使用不完整的类型允许该类型稍后在使用之前完成。您通常会看到前向声明的好处被解释为在使用指向类型的指针时不必在 C++ 中包含包含完整定义的标头,只需要执行class bar 然后bar *,或者当然只需使用@987654330 @ 没有 class bar 行,如果这个特定成员从未使用过。

它也不允许您使用大小不完整的类型作为结构成员(如果大小未知,直到包含此类代码),即使该结构从未用于声明/定义变量。我认为这是因为 struct 是一种类型,并且当您提供类型的完整定义时,您只能执行一次,它必须具有完整的大小,而不是不完整的(具有未知大小的成员),因此该类型将不可用。这个包含不完整结构的结构永远不会被引用,而你可以引用一个不完整大小的不完整类型,而不是一个不完整大小的完整类型(只要你没有用它定义任何东西),并且您可以引用但不能尊重(可以存储地址)类型不完整的指针,因为它具有完整的大小。只要内存的不完整类型不包含不完整的大小,您就可以引用内存。允许在文件/块范围内使用 extern struct i j,因为除非在代码中引用了 j,否则永远不需要它,此时类型必须完整。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-02
    • 1970-01-01
    • 2023-03-12
    • 2012-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多