C中的结构和键入

发布于 2025-02-05 21:21:59 字数 507 浏览 2 评论 0 原文

这篇文章是关于在两部分C代码中理解细节。 为什么还可以:

typedef struct _api_t api_t;

typedef void (*api_set) (api_t * api;
             int a;
  );

typedef int (*api_read) (api_t * api;
  );
  
struct _api_t
{
  api_set set;
  api_read read;
};

这不是

typedef struct _api_t
{
  api_set set;
  api_read read;
} 
api_t;

typedef void (*api_set) (api_t * api;
             int a;
  );

typedef int (*api_read) (api_t * api;
  );

错误:未知类型名称'api_set',错误:未知类型名称'api_read'

This post is about understanding details in two pieces of C code.
Why this is ok:

typedef struct _api_t api_t;

typedef void (*api_set) (api_t * api;
             int a;
  );

typedef int (*api_read) (api_t * api;
  );
  
struct _api_t
{
  api_set set;
  api_read read;
};

and this isn't

typedef struct _api_t
{
  api_set set;
  api_read read;
} 
api_t;

typedef void (*api_set) (api_t * api;
             int a;
  );

typedef int (*api_read) (api_t * api;
  );

error: unknown type name ‘api_set’, error: unknown type name ‘api_read’

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

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

发布评论

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

评论(2

浅浅淡淡 2025-02-12 21:21:59

这些记录

typedef void (*api_set) (api_t * api;
             int a;
  );

typedef int (*api_read) (api_t * api;
  );

是不正确的。编译器应发出错误消息。

看来您的意思是以下代码

typedef struct _api_t api_t;

typedef void (*api_set) (api_t * api, int a );

typedef int (*api_read) (api_t * api  );
  
struct _api_t
{
  api_set set;
  api_read read;
};

此代码是正确的,因为在此结构定义中,

struct _api_t
{
  api_set set;
  api_read read;
};

名称 api_set and api_read (定义为前面的typedef中的函数指针)已经定义用于结构定义。

至于第二个代码段中的结构定义,则尚未定义“ api_set api_set 和 api_read ”的名称 api_set

typedef struct _api_t
{
  api_set set;
  api_read read;
} 
api_t;

未定义。

These records

typedef void (*api_set) (api_t * api;
             int a;
  );

typedef int (*api_read) (api_t * api;
  );

are incorrect. The compiler should issue error messages.

It seems you mean the following code

typedef struct _api_t api_t;

typedef void (*api_set) (api_t * api, int a );

typedef int (*api_read) (api_t * api  );
  
struct _api_t
{
  api_set set;
  api_read read;
};

This code is correct because in this structure definition

struct _api_t
{
  api_set set;
  api_read read;
};

the names api_set and api_read (defined as function pointers in preceding typedefs) are already defined before they are used in the structure definition.

As for the structure definition in the second code snippet then the names api_set and api_read used in the structure definition are not yet defined

typedef struct _api_t
{
  api_set set;
  api_read read;
} 
api_t;

So the compiler will issue error messages that these names are not defined.

绾颜 2025-02-12 21:21:59

关于半分离符作为函数参数的分离器:

typedef void (*api_set) (api_t * api; int a;);

此意外“起作用”,因为有gcc扩展名允许正向声明的函数参数。
如果您以“ pedantic”模式运行汇编,那么您将看到警告:

warning: ISO C forbids forward parameter declarations [-Wpedantic]

参数的正向声明可用于将可变长度数组(VLAA)作为参数的函数有用,因为它允许传递数组size 的参数之后,数组的参数。

  • 没有
void foo(int n, int arr[static n]);

// calling example
int A[3];
foo(3, A);
  • 带有正向声明的
void foo(int n; int arr[static n], int n);

// calling example
int A[3];
foo(A, 3);

前瞻性声明,就提出了即将到来的C23。参见

在您的代码中,两个参数 api and a a 是向前声明,尽管从未真正使用过。结果,这些远期声明被忽略,完整声明等同于:

typedef void (*api_set) ();

哪个指针指向未指定的参数数量和返回 void
可以使用任何数量的参数调用此功能,而不会引起编译器的警告。此外,这种类型是不完整的,因为它与返回的 void 的任何函数兼容,独立于所使用的参数数量和类型。

要解决问题,请使用作为分离器:

typedef void (*api_set) (api_t *api, int a);

此外,请考虑为功能类型而不是功能指针创建别名。它通常会产生清晰的代码:

typedef struct _api_t api_t;

typedef void api_set_f (api_t *, int);
typedef int api_read_f (api_t *);
  
struct _api_t {
  // declare *pointer* to functions
  api_set_f* set;
  api_read_f* read;
};

在第二个示例中,结构 struct _api_t 包含类型 api_set 的成员,但是在解析的此阶段未定义此类型。

About the semicolons as separator of function parameters:

typedef void (*api_set) (api_t * api; int a;);

This accidentally "works" because there is GCC extension allowing forward declarations of function parameters.
If you run the compilation in the "pedantic" mode then you will see the warning:

warning: ISO C forbids forward parameter declarations [-Wpedantic]

The forward declarations of parameters is useful for functions taking Variable-Length Arrays (VLAa) as parameters because it allows to pass a parameter for array size after the parameter for an array.

  • without forward declaration
void foo(int n, int arr[static n]);

// calling example
int A[3];
foo(3, A);
  • with forward declaration
void foo(int n; int arr[static n], int n);

// calling example
int A[3];
foo(A, 3);

This feature was proposed to upcoming C23. See https://www9.open-std.org/JTC1/SC22/WG14/www/docs/n2780.pdf

In your code, the two parameters api and a are forward declared though never actually used. As result those forward declarations are ignored and the full declaration is equivalent to:

typedef void (*api_set) ();

Which a pointer to a function taking unspecified number of arguments and returning void.
This function can be called with any number of arguments without raising a warning from a compiler. Moreover, this kind of type is incomplete as it is compatible with any function returning void independently from number and types of arguments used.

To fix the issue use , as a separator:

typedef void (*api_set) (api_t *api, int a);

Moreover, consider creating an alias for a function type rather than function pointer. It usually results in a clear code:

typedef struct _api_t api_t;

typedef void api_set_f (api_t *, int);
typedef int api_read_f (api_t *);
  
struct _api_t {
  // declare *pointer* to functions
  api_set_f* set;
  api_read_f* read;
};

In the second example the structure struct _api_t contains a member of type api_set, however this type is not defined at this stage of parsing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文