题目一:
在设计一个独立运行于某种微处理器上的c程序时,要求当计算机启动时,调用首地址为0的子例程,请设计该语句:
答案:(* ( void (*) ( ) ) 0 ) ( );
是不是有点懵?让我们来逐步解析;
1:首先void(*p)()认得到么?,这是一个名为p的指针,指向一个返回值为空,参数为空的函数
2:去掉名称,void(*)()则是该函数指针类型;
3:( void (*) () )强制类型转换为函数指针类型
4:( void (*) () )0将int类型的0强制类型转换为函数指针类型
这意思就是在地址0处放着一个指针变量,指向一个无参,返回类型为void的函数;
5:(* ( void (*) ( ) ) 0 ) ( )调用0处地址放的这个函数;
题目二:
void(*signal(int,void(*)(int)))(int)解析该代码什么意思 ;
一:首先signal(int,void(*)(int))为一个函数,signal为函数名,它接受两个参数,一个参数为int,另一个参数为函数指针;
二:这个函数差一个返回类型,它的返回类型就为一个函数指针类型,其函数参数为int,返回值为空,即:void(*)(int)signal(int,void(*)(int))//但这个写法不合规,只是便于理解。
三:其正确写法就为void(*signal(int,void(*)(int)))(int);
这样的写法是不是很复杂,很不方便;于是就有了typedf关键字
typedf
typedf是 C 语言中的一个关键字,用于为已有的类型创建一个新的名字(类型别名)。这使得代码更易读,尤其是在使用复杂类型(如指针、结构体或函数指针)时。
示例:
- 基本类型的别名
typedef unsigned long ulong;
ulong x = 123456789; // x 是 unsigned long 类型,ulong为unsigned long的别名;
2.指针类型的别名
typedef int* IntPtr;
IntPtr p1, p2; // p1 和 p2 都是 int* 类型的指针,IntPtr为int*的别名;
3.结构体类型的别名
typedef struct {
int x;
int y;
} Point;Point p1; // p1 是 Point 类型,Point是struct 的别名
4.函数指针的别名
typedef void (*FuncPtr)(int);
void myFunction(int a) {
// 函数实现
}FuncPtr f = myFunction; // f 是指向函数的指针,FuncPtr是void (*)(int)的别名;
题目二中的void(*signal(int,void(*)(int)))(int)就可以写为
FuncPtr signal(int,void(*)(int))
typedf的优点:
1.简化代码
2.提高可读性:使用类型别名可以使代码更易于理解,尤其是当使用复杂类型时。
3.易于维护:如果需要更改类型,只需修改 typedef
的定义,而不必在代码的多个地方进行修改。
typedf与#define的区别
同时,#define和typedf有相同类似的功能,也能起到重定义的功能
#include <stdio.h>
// 使用 typedef
typedef int* p;int main() {
p a; // a 是 int* 类型
int b = 10;
a = &b;
printf("%d\n", *a); // 输出 10// 使用 #define
#define P int*
P c; // c 是 int* 类型
int d = 20;
c = &d;
printf("%d\n", *c); // 输出 20return 0;
}
虽然也有相同功能,但是#define只是简单的文本替换,适合于常量或简单的宏定义。
在某些场景中使用#define容易出错,比如说:
typedf和#define的陷阱
typedef int* p;
p a,b;//变量a和变量b都是int*类型;
#define p int*
p a,b;//变量a为int*类型,而变量b为整形,因为#define只是简单的文本替换,
p a,b;相当于int * a,b;此时*给了a,a为指针变量,而b则为int类型
所以我们一般
使用 typedef
可以创建更安全、可读性更高的类型别名,适合于复杂类型的定义。
使用 #define
可以进行简单的文本替换,适合于常量或简单的宏定义