typedef精讲

用途一:

  定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如:

  char* pa, pb; // 这多数不符合我们的意图,它只声明了一个指向字符变量的指针,

  // 和一个字符变量;

  以下则可行:

  typedef char* PCHAR; // 一般用大写

  PCHAR pa, pb; // 可行,同时声明了两个指向字符变量的指针

  虽然:

  char *pa, *pb;

  也可行,但相对来说没有用typedef的形式直观,尤其在需要大量指针的地方,typedef的方式更省事。

用途二:

  用在旧的C代码中(具体多旧没有查),帮助struct.以前的代码中,声明struct新对象时,必须要带上struct,即形式为: struct 结构名 对象名,如:

  struct tagPOINT1

  {

  int x;

  int y;

  };

  struct tagPOINT1 p1;

  而在C++中,则可以直接写:结构名 对象名,即:

  tagPOINT1 p1;

  估计某人觉得经常多写一个struct太麻烦了,于是就发明了:

  typedef struct tagPOINT

  {

  int x;

  int y;

  }POINT;

  POINT p1; // 这样就比原来的方式少写了一个struct,比较省事,尤其在大量使用的时候

  或许,在C++中,typedef的这种用途二不是很大,但是理解了它,对掌握以前的旧代码还是有帮助的,毕竟我们在项目中有可能会遇到较早些年代遗留下来的代码。

 

用途三:

  用typedef来定义与平台无关的类型。

  比如定义一个叫 REAL 的浮点类型,在目标平台一上,让它表示最高精度的类型为:

  typedef long double REAL;

  在不支持 long double 的平台二上,改为:

  typedef double REAL;

  在连 double 都不支持的平台三上,改为:

  typedef float REAL;

  也就是说,当跨平台时,只要改下 typedef 本身就行,不用对其他源码做任何修改。

  标准库就广泛使用了这个技巧,比如size_t.

  另外,因为typedef是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健(虽然用宏有时也可以完成以上的用途)。


用途四:

  为复杂的声明定义一个新的简单的别名。方法是:在原来的声明里逐步用别名替换一部分复杂声明,如此循环,把带变量名的部分留到最后替换,得到的就是原声明的最简化版。举例:

  1. 原声明:int *(*a[5])(int, char*);

  变量名为a,直接用一个新别名pFun替换a就可以了:

  typedef int *(*pFun)(int, char*);

  原声明的最简化版:

  pFun a[5];

  2. 原声明:void (*b[10]) (void (*)());

  变量名为b,先替换右边部分括号里的,pFunParam为别名一:

  typedef void (*pFunParam)();

  再替换左边的变量b,pFunx为别名二:

  typedef void (*pFunx)(pFunParam);

  原声明的最简化版:

  pFunx b[10];

  3. 原声明:doube(*)() (*e)[9];

  变量名为e,先替换左边部分,pFuny为别名一:

  typedef double(*pFuny)();

  再替换右边的变量e,pFunParamy为别名二

  typedef pFuny (*pFunParamy)[9];

  原声明的最简化版:

  pFunParamy e;

  理解复杂声明可用的"右左法则":从变量名看起,先往右,再往左,碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直到整个声明分析完。举例:

  int (*func)(int *p);

  首先找到变量名func,外面有一对圆括号,而且左边是一个*号,这说明func是一个指针;然后跳出这个圆括号,先看右边,又遇到圆括号,这说明(*func)是一个函数,所以func是一个指向这类函数的指针,即函数指针,这类函数具有int*类型的形参,返回值类型是int.

  int (*func[5])(int *);

  func右边是一个[]运算符,说明func是具有5个元素的数组;func的左边有一个*,说明func的元素是指针(注意这里的*不是修饰func,而是修饰func[5]的,原因是[]运算符优先级比*高,func先跟[]结合)。跳出这个括号,看右边,又遇到圆括号,说明func数组的元素是函数类型的指针,它指向的函数具有int*类型的形参,返回值类型为int.

  也可以记住2个模式:

  type (*)(…)函数指针

  type (*)[]数组指针

陷阱一

  记住,typedef是定义了一种类型的新别名,不同于宏,它不是简单的字符串替换。比如:

  先定义:

  typedef char* PSTR;

  然后:

  int mystrcmp(const PSTR, const PSTR);

  const PSTR实际上相当于const char*吗?不是的,它实际上相当于char* const.

  原因在于const给予了整个指针本身以常量性,也就是形成了常量指针char* const.

  简单来说,记住当const和typedef一起出现时,typedef不会是简单的字符串替换就行。

陷阱二:

  typedef在语法上是一个存储类的关键字(如auto、extern、mutable、static、register等一样),虽然它并不真正影响对象的存储特性,如:

  typedef static int INT2; //不可行

  编译将失败,会提示"指定了一个以上的存储类".

<think>我们被要求详细讲解C语言中的设计模式。设计模式是解决特定问题的模板,它们可以帮助开发者编写更清晰、更易于维护的代码。虽然设计模式通常与面向对象语言(如C++或Java)相关联,但也可以在C语言中实现,尽管C语言不支持类和继承等面向对象特性。 根据提供的引用,我们可以知道站内有一些关于C语言设计模式的文章,包括建造者模式、桥接模式、职责链模式和命令模式等。我们将以这些模式为例,详细讲解如何在C语言中实现设计模式。 由于C语言是过程式语言,我们将使用结构体、函数指针等特性来模拟面向对象的设计模式。 ### 1. 命令模式(Command Pattern) 命令模式将请求封装为一个对象,从而允许用户使用不同的请求、队列或日志请求来参数化其他对象,并支持可撤销的操作。 在C语言中,我们可以这样实现命令模式: - 定义一个命令接口(使用函数指针) - 具体命令结构体包含执行命令的函数指针和接收者(即命令操作的对象) - 调用者(Invoker)通过调用命令对象来执行请求 参考引用[5]中的例子: ```c // 接收者:电视机 typedef struct TV { int isOn; } TV; TV* TV_Create() { TV* tv = (TV*)malloc(sizeof(TV)); if (tv) tv->isOn = 0; return tv; } void TV_TurnOn(TV* tv) { tv->isOn = 1; printf("TV is now ON\n"); } void TV_TurnOff(TV* tv) { tv->isOn = 0; printf("TV is now OFF\n"); } // 命令接口 typedef struct Command { void (*execute)(struct Command*, TV*); } Command; // 具体命令:打开电视 typedef struct TurnOnCommand { Command base; } TurnOnCommand; void TurnOnCommand_execute(Command* command, TV* tv) { TV_TurnOn(tv); } TurnOnCommand* TurnOnCommand_Create() { TurnOnCommand* cmd = (TurnOnCommand*)malloc(sizeof(TurnOnCommand)); if (cmd) cmd->base.execute = TurnOnCommand_execute; return cmd; } // 具体命令:关闭电视 typedef struct TurnOffCommand { Command base; } TurnOffCommand; void TurnOffCommand_execute(Command* command, TV* tv) { TV_TurnOff(tv); } TurnOffCommand* TurnOffCommand_Create() { TurnOffCommand* cmd = (TurnOffCommand*)malloc(sizeof(TurnOffCommand)); if (cmd) cmd->base.execute = TurnOffCommand_execute; return cmd; } // 调用者:遥控器 typedef struct RemoteControl { Command* onCommand; Command* offCommand; } RemoteControl; RemoteControl* RemoteControl_Create() { return (RemoteControl*)malloc(sizeof(RemoteControl)); } void RemoteControl_SetCommand(RemoteControl* remote, Command* onCmd, Command* offCmd) { remote->onCommand = onCmd; remote->offCommand = offCmd; } void RemoteControl_PressOn(RemoteControl* remote, TV* tv) { if (remote->onCommand) remote->onCommand->execute(remote->onCommand, tv); } void RemoteControl_PressOff(RemoteControl* remote, TV* tv) { if (remote->offCommand) remote->offCommand->execute(remote->offCommand, tv); } int main() { TV* tv = TV_Create(); TurnOnCommand* onCmd = TurnOnCommand_Create(); TurnOffCommand* offCmd = TurnOffCommand_Create(); RemoteControl* remote = RemoteControl_Create(); RemoteControl_SetCommand(remote, (Command*)onCmd, (Command*)offCmd); // 使用遥控器打开电视 RemoteControl_PressOn(remote, tv); // 关闭电视 RemoteControl_PressOff(remote, tv); // 释放内存 free(tv); free(onCmd); free(offCmd); free(remote); return 0; } ``` 在这个例子中,命令模式解耦了发送者(遥控器)和接收者(电视),使得我们可以轻松添加新的命令而不改变遥控器的代码。 ### 2. 桥接模式(Bridge Pattern) 桥接模式将抽象部分与实现部分分离,使它们可以独立变化。在C语言中,我们可以用两个层次结构来实现:一个抽象层次和一个实现层次。 引用[3]中的例子: ```c // 实现部分:渲染器接口 typedef struct Renderer { void (*render_circle)(struct Renderer*, float x, float y, float radius); void (*render_rectangle)(struct Renderer*, float x, float y, float width, float height); } Renderer; // 具体渲染器:OpenGL typedef struct OpenGLRenderer { Renderer base; } OpenGLRenderer; void OpenGL_render_circle(Renderer* renderer, float x, float y, float radius) { printf("OpenGL: Drawing circle at (%f, %f) with radius %f\n", x, y, radius); } void OpenGL_render_rectangle(Renderer* renderer, float x, float y, float width, float height) { printf("OpenGL: Drawing rectangle at (%f, %f) with width %f and height %f\n", x, y, width, height); } OpenGLRenderer* OpenGLRenderer_Create() { OpenGLRenderer* r = (OpenGLRenderer*)malloc(sizeof(OpenGLRenderer)); if (r) { r->base.render_circle = OpenGL_render_circle; r->base.render_rectangle = OpenGL_render_rectangle; } return r; } // 具体渲染器:DirectX typedef struct DirectXRenderer { Renderer base; } DirectXRenderer; void DirectX_render_circle(Renderer* renderer, float x, float y, float radius) { printf("DirectX: Drawing circle at (%f, %f) with radius %f\n", x, y, radius); } void DirectX_render_rectangle(Renderer* renderer, float x, float y, float width, float height) { printf("DirectX: Drawing rectangle at (%f, %f) with width %f and height %f\n", x, y, width, height); } DirectXRenderer* DirectXRenderer_Create() { DirectXRenderer* r = (DirectXRenderer*)malloc(sizeof(DirectXRenderer)); if (r) { r->base.render_circle = DirectX_render_circle; r->base.render_rectangle = DirectX_render_rectangle; } return r; } // 抽象部分:形状 typedef struct Shape { Renderer* renderer; void (*draw)(struct Shape*); // 绘制函数 } Shape; // 具体形状:圆形 typedef struct Circle { Shape base; float x, y, radius; } Circle; void Circle_draw(Shape* shape) { Circle* circle = (Circle*)shape; circle->base.renderer->render_circle(circle->base.renderer, circle->x, circle->y, circle->radius); } Circle* Circle_Create(Renderer* renderer, float x, float y, float radius) { Circle* c = (Circle*)malloc(sizeof(Circle)); if (c) { c->base.renderer = renderer; c->base.draw = Circle_draw; c->x = x; c->y = y; c->radius = radius; } return c; } // 具体形状:矩形 typedef struct Rectangle { Shape base; float x, y, width, height; } Rectangle; void Rectangle_draw(Shape* shape) { Rectangle* rect = (Rectangle*)shape; rect->base.renderer->render_rectangle(rect->base.renderer, rect->x, rect->y, rect->width, rect->height); } Rectangle* Rectangle_Create(Renderer* renderer, float x, float y, float width, float height) { Rectangle* r = (Rectangle*)malloc(sizeof(Rectangle)); if (r) { r->base.renderer = renderer; r->base.draw = Rectangle_draw; r->x = x; r->y = y; r->width = width; r->height = height; } return r; } int main() { // 创建两种渲染器 OpenGLRenderer* opengl = OpenGLRenderer_Create(); DirectXRenderer* directx = DirectXRenderer_Create(); // 创建两个圆形,分别使用不同的渲染器 Circle* circle1 = Circle_Create((Renderer*)opengl, 10, 10, 5); Circle* circle2 = Circle_Create((Renderer*)directx, 20, 20, 8); // 创建两个矩形 Rectangle* rect1 = Rectangle_Create((Renderer*)opengl, 5, 5, 10, 20); Rectangle* rect2 = Rectangle_Create((Renderer*)directx, 15, 15, 30, 40); // 绘制 circle1->base.draw((Shape*)circle1); circle2->base.draw((Shape*)circle2); rect1->base.draw((Shape*)rect1); rect2->base.draw((Shape*)rect2); // 释放内存 free(circle1); free(circle2); free(rect1); free(rect2); free(opengl); free(directx); return 0; } ``` 桥接模式允许我们独立地扩展形状和渲染器,而不需要修改对方。 ### 3. 建造者模式(Builder Pattern) 建造者模式用于创建复杂对象,将构建过程和表示分离。在C语言中,我们可以定义一个建造者接口,然后由具体的建造者实现这个接口来构建产品的不同部分。 引用[1]中的汽车建造例子: ```c // 产品:汽车 typedef struct Car { char* engine; char* wheels; char* body; } Car; Car* Car_Create() { return (Car*)malloc(sizeof(Car)); } void Car_SetEngine(Car* car, const char* engine) { car->engine = strdup(engine); } void Car_SetWheels(Car* car, const char* wheels) { car->wheels = strdup(wheels); } void Car_SetBody(Car* car, const char* body) { car->body = strdup(body); } void Car_Describe(Car* car) { printf("Car with engine: %s, wheels: %s, body: %s\n", car->engine, car->wheels, car->body); } void Car_Destroy(Car* car) { free(car->engine); free(car->wheels); free(car->body); free(car); } // 建造者接口 typedef struct CarBuilder { Car* car; void (*build_engine)(struct CarBuilder*, const char*); void (*build_wheels)(struct CarBuilder*, const char*); void (*build_body)(struct CarBuilder*, const char*); Car* (*get_result)(struct CarBuilder*); } CarBuilder; // 具体建造者 typedef struct SedanCarBuilder { CarBuilder base; } SedanCarBuilder; void Sedan_build_engine(CarBuilder* builder, const char* engine) { Car_SetEngine(builder->car, engine); } void Sedan_build_wheels(CarBuilder* builder, const char* wheels) { Car_SetWheels(builder->car, wheels); } void Sedan_build_body(CarBuilder* builder, const char* body) { Car_SetBody(builder->car, body); } Car* Sedan_get_result(CarBuilder* builder) { return builder->car; } SedanCarBuilder* SedanCarBuilder_Create() { SedanCarBuilder* builder = (SedanCarBuilder*)malloc(sizeof(SedanCarBuilder)); if (builder) { builder->base.car = Car_Create(); builder->base.build_engine = Sedan_build_engine; builder->base.build_wheels = Sedan_build_wheels; builder->base.build_body = Sedan_build_body; builder->base.get_result = Sedan_get_result; } return builder; } // 导演:控制建造过程 typedef struct Director { CarBuilder* builder; } Director; Director* Director_Create(CarBuilder* builder) { Director* director = (Director*)malloc(sizeof(Director)); if (director) director->builder = builder; return director; } Car* Director_construct(Director* director) { director->builder->build_engine(director->builder, "V6"); director->builder->build_wheels(director->builder, "17-inch"); director->builder->build_body(director->builder, "Sedan"); return director->builder->get_result(director->builder); } int main() { SedanCarBuilder* sedanBuilder = SedanCarBuilder_Create(); Director* director = Director_Create((CarBuilder*)sedanBuilder); Car* sedan = Director_construct(director); Car_Describe(sedan); // 释放内存 Car_Destroy(sedan); free(sedanBuilder); free(director); return 0; } ``` 建造者模式使得创建复杂对象的过程更加清晰,并且可以复用相同的构建过程来创建不同的产品。 ### 4. 职责链模式(Chain of Responsibility Pattern) 职责链模式为请求创建一个接收者对象的链,每个接收者都有机会处理请求或将其传递给下一个接收者。 引用[4]中的例子: ```c // 处理者接口 typedef struct Handler { struct Handler* next; void (*handle_request)(struct Handler*, int request); } Handler; void Handler_set_next(Handler* handler, Handler* next) { handler->next = next; } // 具体处理者:具体处理者A typedef struct ConcreteHandlerA { Handler base; } ConcreteHandlerA; void handle_request_A(Handler* handler, int request) { if (request < 10) { printf("ConcreteHandlerA handled request %d\n", request); } else if (handler->next) { handler->next->handle_request(handler->next, request); } else { printf("No handler for request %d\n", request); } } ConcreteHandlerA* ConcreteHandlerA_Create() { ConcreteHandlerA* handler = (ConcreteHandlerA*)malloc(sizeof(ConcreteHandlerA)); if (handler) { handler->base.handle_request = handle_request_A; handler->base.next = NULL; } return handler; } // 具体处理者:具体处理者B typedef struct ConcreteHandlerB { Handler base; } ConcreteHandlerB; void handle_request_B(Handler* handler, int request) { if (request >= 10 && request < 20) { printf("ConcreteHandlerB handled request %d\n", request); } else if (handler->next) { handler->next->handle_request(handler->next, request); } else { printf("No handler for request %d\n", request); } } ConcreteHandlerB* ConcreteHandlerB_Create() { ConcreteHandlerB* handler = (ConcreteHandlerB*)malloc(sizeof(ConcreteHandlerB)); if (handler) { handler->base.handle_request = handle_request_B; handler->base.next = NULL; } return handler; } int main() { ConcreteHandlerA* handlerA = ConcreteHandlerA_Create(); ConcreteHandlerB* handlerB = ConcreteHandlerB_Create(); Handler_set_next((Handler*)handlerA, (Handler*)handlerB); int requests[] = {5, 15, 25}; for (int i = 0; i < 3; i++) { handlerA->base.handle_request((Handler*)handlerA, requests[i]); } free(handlerA); free(handlerB); return 0; } ``` 职责链模式允许多个对象处理请求,从而降低请求发送者和接收者之间的耦合。 ### 总结 在C语言中实现设计模式需要利用结构体和函数指针来模拟面向对象的行为。以上我们展示了四种设计模式在C语言中的实现: 1. 命令模式:封装请求为对象,支持撤销和队列操作。 2. 桥接模式:分离抽象和实现,使它们可以独立变化。 3. 建造者模式:分步构建复杂对象,使得相同的构建过程可以创建不同的表示。 4. 职责链模式:将请求沿着处理链传递,直到有对象处理它。 这些模式在C语言中同样有效,能够提高代码的模块化、可维护性和可扩展性。 §§相关问题§§ 1. C语言中如何实现单例模式? 2. 在C语言中如何实现观察者模式? 3. 设计模式在C语言项目中的实际应用案例有哪些? 4. 如何管理C语言设计模式实现中的内存以避免泄漏?</think>### C语言设计模式详解 设计模式是解决特定问题的可复用模板,在C语言中可通过结构体、函数指针和回调函数等特性实现。以下结合站内资料详细解析5种经典设计模式: #### 1. 命令模式(Command Pattern) **核心思想**:将请求封装为对象,实现请求发送者与接收者的解耦[^5]。 ```c // 命令接口 typedef struct Command { void (*execute)(void*); } Command; // 具体命令:打开电视 typedef struct TurnOnCommand { Command base; TV* receiver; // 接收者对象 } TurnOnCommand; void execute_turn_on(void* cmd) { TurnOnCommand* c = (TurnOnCommand*)cmd; tv_turn_on(c->receiver); // 调用接收者方法 } // 调用者:遥控器 typedef struct RemoteControl { Command* on_command; } RemoteControl; void press_button(RemoteControl* remote) { remote->on_command->execute(remote->on_command); } ``` **优势**: - 解耦调用者和接收者 - 支持命令队列和撤销操作 - 新增命令无需修改现有代码[^5] #### 2. 桥接模式(Bridge Pattern) **核心思想**:分离抽象与实现,使两者可独立变化[^3]。 ```c // 渲染器接口(实现层) typedef struct Renderer { void (*draw_circle)(float x, float y, float r); } Renderer; // OpenGL实现 void opengl_draw_circle(float x, float y, float r) { printf("OpenGL: Circle at (%.1f,%.1f) r=%.1f\n", x, y, r); } // 形状抽象层 typedef struct Shape { Renderer* renderer; void (*draw)(struct Shape*); } Shape; // 具体圆形 typedef struct Circle { Shape base; float x, y, radius; } Circle; void circle_draw(Shape* shape) { Circle* c = (Circle*)shape; c->base.renderer->draw_circle(c->x, c->y, c->radius); } ``` **应用场景**: - 跨平台图形渲染(OpenGL/DirectX) - 设备驱动抽象层 - 数据库连接器实现[^3] #### 3. 建造者模式(Builder Pattern) **核心思想**:分步构建复杂对象,隔离构建过程与表示[^1]。 ```c // 产品:汽车 typedef struct Car { char* engine; char* wheels; char* body; } Car; // 建造者接口 typedef struct CarBuilder { void (*set_engine)(struct CarBuilder*, const char*); void (*set_wheels)(struct CarBuilder*, const char*); void (*set_body)(struct CarBuilder*, const char*); Car* (*get_result)(struct CarBuilder*); } CarBuilder; // 导演类控制构建流程 Car* construct_sports_car(CarBuilder* builder) { builder->set_engine(builder, "V8"); builder->set_wheels(builder, "Racing"); builder->set_body(builder, "Carbon Fiber"); return builder->get_result(builder); } ``` **适用场景**: - 需要创建不同配置的复杂对象 - 对象创建过程需精确控制 - 产品组成部分的构造算法需要独立[^1] #### 4. 职责链模式(Chain of Responsibility) **核心思想**:多个对象依次处理请求,避免请求发送者与接收者耦合[^4]。 ```c // 处理器接口 typedef struct Handler { struct Handler* next; void (*handle_request)(struct Handler*, int req); } Handler; // 具体处理器A void handle_a(Handler* h, int req) { if (req < 100) printf("Handler A processed\n"); else if (h->next) h->next->handle_request(h->next, req); } // 客户端调用 void process_request(Handler* chain, int req) { chain->handle_request(chain, req); } ``` **优势**: - 动态调整处理链顺序 - 新增处理器无需修改核心逻辑 - 请求发送者无需知道具体处理者[^4] #### 5. 单例模式(Singleton Pattern) **核心思想**:确保类仅有一个实例并提供全局访问点。 ```c // 全局静态实例 static Logger* instance = NULL; Logger* get_logger() { if (instance == NULL) { instance = (Logger*)malloc(sizeof(Logger)); // 初始化操作 } return instance; } ``` **注意事项**: - 多线程环境下需加锁 - 谨慎使用全局状态 - 避免循环依赖 ### 内存管理关键点 在C语言实现设计模式时: 1. 使用`malloc/calloc`分配对象内存 2. 通过函数指针实现多态行为 3. 必须用`free`释放资源,防止内存泄漏[^2] 4. 建议使用Valgrind检测内存错误[^2] ### 设计模式选择原则 | 场景 | 推荐模式 | 优势 | |------|----------|------| | 算法替换 | 策略模式 | 运行时切换算法 | | 对象创建 | 工厂方法 | 解耦客户端与具体类 | | 跨平台 | 桥接模式 | 分离抽象与实现 | | 请求处理 | 职责链 | 动态添加处理器 | | 状态管理 | 状态模式 | 封装状态转换逻辑 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值