问题描述
我试图了解用C语言编写的固件,该固件驱动芯片进行超宽带连接。
固件大量使用typedef
和指针。我已经了解了固件背后的大多数想法,但是有一个我无法理解的typedef void
功能。
基本上,固件会创建一个结构来保存设备数据,
typedef struct
{
//some data
dwt_cb_t cbTxDone; // Callback for TX confirmation event
//some other data
} dwt_local_data_t ;
我了解该结构名为 dwt_local_data_t ,其中包含一些变量,包括这种奇怪的 dwt_cb_t 类型。
在.h文件中, dwt_cb_t 被命名为
// Call-back type for all events
typedef void (*dwt_cb_t)(const dwt_cb_data_t *);
其中 dwt_cb_data_t 是
形式的另一种结构typedef struct
{
uint32 status; //initial value of register as ISR is entered
uint16 datalength; //length of frame
uint8 fctrl[2]; //frame control bytes
uint8 rx_flags; //RX frame flags,see above
} dwt_cb_data_t;
现在,我试图理解typedef void (*dwt_cb_t)(const dwt_cb_data_t *);
据我了解,typedef void
是一种指向函数的指针。它定义了一个变量 dwt_cb_t ,该变量指向一个函数,该函数接收常量结构 dwt_cb_data_t
我不知道我的推理是否正确,因为我不明白为什么 dwt_cb_data_t 的末尾有一个*
。这是否意味着函数的输入是结构的指针?在这种情况下,为什么不写typedef void (*dwt_cb_t)(const *dwt_cb_data_t);
呢?
解决方法
停止思考typedef void
。您正在以这种方式截断定义。
定义的符号为dwt_cb_t
,它是类型void (*)(const dwt_cb_data_t *)
的别名,即类型:指向带有const dwt_cb_data_t *
参数并返回void
的函数的指针。
在C ++中,您将编写:
using dwt_cb_t = void (*)(const dwt_cb_data_t *);
这很清楚。
,是否表示该函数的输入是该函数的指针 结构?
是的,它表示函数的参数是指向该结构的指针。
在这种情况下,为什么不写
typedef void (*dwt_cb_t)(const*dwt_cb_data_t);
相反?
这是因为指针符号*
必须放置在标识符之前,而不是标识符的类型之前。
在这种情况下,您可以看到如下功能:
typedef void (*dwt_cb_t)(const dwt_cb_data_t *var);
唯一的是省略了var
。
现在,我正试图了解
的含义。typedef void (*dwt_cb_t)(const dwt_cb_data_t *);
typedef void (*dwt_cb_t)(const dwt_cb_data_t *);
是指定义类型dwt_cb_t
,该类型是指向返回void
并接受类型const dwt_cb_data_t *
的一个参数的函数的指针。
如果您有功能,例如
void func(const dwt_cb_data_t * data); // func accepts argument type
const dwt_cb_data_t *,returns void
你可以写
dwt_cb_t f = func;
,
为了更加清楚,我们假设有一个声明为
的函数void f( int *x );
函数的类型为void( int * )
。
您可以为此函数类型引入别名,例如
typedef void Func( int * );
并使用别名声明(但未定义)函数
这是一个演示程序。
#include <stdio.h>
typedef void Func( int * );
Func f;
int main(void)
{
int x = 0;
printf( "x = %d\n",x );
f( &x );
printf( "x = %d\n",x );
return 0;
}
void f( int *x )
{
++*x;
}
程序输出为
x = 0
x = 1
请注意,您也可以通过以下方式声明函数别名
void typedef Func( int * );
现在让我们为该函数类型的函数指针声明一个别名。
您可以简单地写
typedef void Func( int * );
和
typedef Func *FuncPtr;
这是一个演示程序。
#include <stdio.h>
typedef void Func( int * );
Func f;
typedef Func *FuncPtr;
int main(void)
{
int x = 0;
printf( "x = %d\n",x );
FuncPtr fp = f;
fp( &x );
printf( "x = %d\n",x );
return 0;
}
void f( int *x )
{
++*x;
}
另一方面,您可以为函数类型的指针声明别名,而无需为函数类型使用别名。
#include <stdio.h>
typedef void Func( int * );
Func f;
typedef void ( *FuncPtr )( int * );
int main(void)
{
int x = 0;
printf( "x = %d\n",x );
return 0;
}
void f( int *x )
{
++*x;
}
现在比较这些别名声明
typedef void ( *FuncPtr )( int * );
typedef void (*dwt_cb_t)(const dwt_cb_data_t *);
唯一的区别是参数的类型。在第一个声明中,参数的类型为int *
,而在第二个声明中,参数的类型为const dwt_cb_data_t *
。
在C ++中,您可以使用typedef作为声明
using dwt_cb_t = void (*)(const dwt_cb_data_t *);
在C ++中使用别名声明更加灵活,因为您可以使用模板别名声明。
这是一个演示程序。
#include <iostream>
template <typename T>
using FuncPtr = void ( * )( T * );
template <typename T>
void f( T *t )
{
++*t;
}
int main()
{
FuncPtr<int> fp1 = f;
FuncPtr<char> fp2 = f;
int x = 0;
char c = 'A';
fp1( &x );
fp2( &c );
std::cout << "x = " << x << '\n';
std::cout << "c = " << c << '\n';
return 0;
}
程序输出为
x = 1
c = B
,
typedef void (*dwt_cb_t)(const dwt_cb_data_t *);
这仅表示dwt_cb_data_t
是数据类型,而dwt_cb_data_t *
仅仅是指向它的指针。
函数原型只是缺少形式参数名称,这很好。 逐步的版本是:
int myFunc(int,char*); // no formal parameter name,just its datatype
然后在实现中,您将看到
int myFunc(int var1,char* var_ptr){
//function body
}
不用参数名就更容易阅读。