char (*(*p[3])( int ))[5] 等等一系列

本文详细解读了C语言中复杂指针声明的右左法则,并通过实例展示了如何运用此法则来理解复杂的指针声明。同时介绍了如何使用typedef简化声明,增强了代码的可读性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:csdnblog

看这个:


C指针声明解读之左右法则
C语言所有复杂的指针声明,都是由各种声明嵌套构成的。如何解读复杂指针声明呢?右左法则是一个既著名又常用的方法。不过,右左法则其实并不是C标准里面的内容,它是从C标准的声明规定中归纳出来的方法。C标准的声明规则,是用来解决如何创建声明的,而右左法则是用来解决如何辩识一个声明的,两者可以说是相反的。右左法则的英文原文是这样说的:
  The right-left rule: Start reading the declaration from the innermost parentheses, go right, and then go left. When you encounter parentheses, the direction should be reversed. Once everything in the parentheses has been parsed, jump out of it. Continue till the whole declaration has been parsed.  

这段英文的翻译如下:

  右左法则:首先从最里面的圆括号内未定义的标识符开始阅读看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。

  总之对声明进行分析,最根本的方法还是按优先级和结合性来类比替换,从那些最基本的声明进行类比,简化,从而进行理解。下面分析几个例子,来具体阐述如何使用这种方法。

#1:int* (*a[5])(int, char*);

  首先看到标识符名a,"[]"优先级大于"*",a与"[5]"先结合。所以a是一个数组,这个数组有5个元素,每一个元素都是一个指针,指针指向"int* (int, char*)",很明显,指向的是一个函数,这个函数参数是"int, char*",返回值是"int*"。OK,结束了一个。:)

#2:void (*b[10]) (void (*)());

  b是一个数组,这个数组有10个元素,每一个元素都是一个指针,指针指向一个函数,函数参数是"void (*)()"【注:这也是一个函数指针, 参数为空,返回为void】,返回值是"void"。完毕!

#3:int(*)() (*c)[9];

   c是一个指针,指针指向一个数组,这个数组有9个元素,每一个元素都是"int(*)()"(也即一个函数指针,指向一个函数,这个函数的参数为空,返回值是int型)。


#4:int (*(*d)[5])(int *);

  (*d)------指针;
  (*d)[5]------这个指针指向一个数组;
  *(*d)[5]------这个数组中每个元素都是指针类型;
  int (int *)------ 什么类型的指针?这个类型的。
    
    
#5:int (*(*e)(int *))[5];  
  *e-----向右遇到括号,向左遇到*,说明e是个指针,啥指针呢?
  (*e)(int *)------跳出括号向右遇到(int *),说明这个指针是个函数指针,形参为int*, 返回值为何?且听下回分解:);
  *(*e)(int *)------返回值为何?向右遇到括号,再向左,喔,遇到*了,那就是返回了一个指针了。啥指针呢? 同样地,下回分解;
  (*(*e)(int *))[5]-------向右遇到[],说明那是个指向数组的指针,是啥数组呢?不急,慢慢来;
  int (*(*e)(int *))[5]-------向左遇到int,喔,明白了,就是个简单的整型数组。OVER

    
  当然实际当中,当需要声明一个复杂指针时,如果把整个声明写成上面所示的形式,对程序可读性将是一个巨大损害。谁要是写出这样BT的指针声明,那就真是丢rp了,估计会被骂死!。
  还是用typedef来对声明逐层分解替换下吧,增强可读性。

  例如对于上面的声明:int (*(*func)(int *))[5]; 可以这样分解:
  typedef int (*pArr)[5];  
  typedef pArr (*func)(int *);  
  这样就容易读得多了啊!


  再看看这个啥意思? typedef int (* (* (*FUNC)(int *) )[5] )(int *); ---- 晕了吧。

  其实typedef int (* (* (*FUNC)(int *) )[5] )(int *);  
  等价与下面的:)

  typedef int (*PF)(int *);

  typedef PF (*PARRAY)[5];

  typedef PARRAY (*FUNC)(int *);

  (*(void (*)())0)();------->这个呢?
  按左右法则:
  (void (*)()) -----是一个返回值为void,参数为空的函数指针原型。
  (void (*)())0-----把0强转成一个返回值为void,参数为空的函数指针,指针指向的地址为0.
  *(void (*)())0-----前面加上*表示整个是一个返回值为void的函数的名字
  (*(void (*)())0)()------这当然就是一个函数调用了。

  再typedef化简下:
  typedef void (*pf)();
  (*(pf)0)();
#include "ti_msp_dl_config.h" #include "tjc_usart_hmi.h" #include <stdio.h> #include <stdint.h> #include <stdbool.h> #include <ti/driverlib/dl_uart.h> #include <ti/devices/msp/msp.h> #include <ti/driverlib/driverlib.h> #include <ti/driverlib/dl_common.h> // 红外协议时序宏 (单位:微秒) #define LEADER_HIGH 9000 // 引导码高电平9ms #define LEADER_LOW 4500 // 引导码低电平4.5ms #define BIT_HIGH 560 // 数据位高电平560μs #define BIT_ONE_LOW 1690 // 逻辑"1"低电平1690μs #define BIT_ZERO_LOW 560 // 逻辑"0"低电平560μs #define TOLERANCE 150 // 时序容差±150μs #define SYSTEM_CLOCK 32000000 //// 32MHz // 安全参数 #define MAX_RETRY 3 // 最大重试次数 #define LOCK_TIME 15000 // 锁定时间(ms) #define TIME_WINDOW 3000 // 时间容错窗口(±3000ms) // 淘晶驰屏定义 #define TJC_PAGE_MAIN 0 #define TJC_TEXT_STATUS "t0" #define TJC_TEXT_TIME "t1" #define TJC_BUTTON_RESET "b0" // 全局变量 volatile uint32_t delay_value __attribute__((section(".bss"))); volatile uint8_t retry_count __attribute__((section(".bss"))); volatile uint32_t last_fail_time __attribute__((section(".bss"))); volatile uint32_t rtc_counter __attribute__((section(".bss"))); volatile uint32_t now_time __attribute__((section(".bss"))); #define GLOBAL_VARS_BASE 0x20000000 typedef struct { volatile uint32_t delay_value; volatile uint8_t retry_count; volatile uint32_t last_fail_time; volatile uint32_t rtc_counter; volatile uint32_t now_time; volatile uint32_t last_time; volatile uint32_t counter; char str[50]; } GlobalVars; volatile GlobalVars* const globals = (GlobalVars*)GLOBAL_VARS_BASE; /******************** 淘晶驰串口屏驱动 ********************/ void tjc_send_cmd(const char *cmd) { // 发送命令主体 const char *p = cmd; while(*p) { while(!DL_UART_isTXFIFOEmpty(UART_0_INST)); // 等待发送完成 DL_UART_transmitData(UART_0_INST, *p++); } // 发送TJC协议结束符(0xFF 0xFF 0xFF) for(uint8_t i = 0; i < 3; i++) { while(!DL_UART_isTXFIFOEmpty(UART_0_INST)); DL_UART_transmitData(UART_0_INST, 0xFF); } } void tjc_set_text(const char *obj_name, const char *text) { char cmd[128]; snprintf(cmd, sizeof(cmd), "%s.txt=\"%s\"", obj_name, text); tjc_send_cmd(cmd); } void tjc_change_page(uint8_t page_id) { char cmd[16]; snprintf(cmd, sizeof(cmd), "page %d", page_id); tjc_send_cmd(cmd); } void tjc_beep(uint16_t duration_ms) { char cmd[16]; snprintf(cmd, sizeof(cmd), "beep %u", duration_ms); tjc_send_cmd(cmd); } /******************** 系统基础功能 ********************/ void delay_us(uint32_t us) { delay_value = us; while(delay_value != 0); } void SysTick_Handler(void) { if(delay_value > 0) delay_value--; rtc_counter++; // 简单的RTC计数器(每毫秒增加1) now_time = rtc_counter; // 更新全局时间 } uint32_t get_timestamp(void) { return rtc_counter; } /******************** 红外解码功能(8位) ********************/ bool validate_dynamic_code(uint8_t rx_code) { uint32_t current_seed = get_timestamp(); for(int offset = -TIME_WINDOW; offset <= TIME_WINDOW; offset++) { uint32_t seed = current_seed + offset; uint32_t calc_code = (seed * 0x5DEECE66D) & 0xFFFFFFFF; // 比较低8位 if(rx_code == (calc_code & 0xFF)) return true; } return false; } uint8_t ir_receive_packet(void) { uint8_t data = 0; uint32_t start_time = 0; uint32_t duration = 0; // 1. 检测引导码 while(DL_GPIO_readPins(GPIOA, DL_GPIO_PIN_9) == 1); // 等待高电平结束 start_time = get_timestamp(); while(DL_GPIO_readPins(GPIOA, DL_GPIO_PIN_9) == 0); // 等待低电平结束 duration = get_timestamp() - start_time; // 检查引导码低电平部分是否符合要求(转换为毫秒) if(duration < (LEADER_HIGH/1000 - TOLERANCE/1000) || duration > (LEADER_HIGH/1000 + TOLERANCE/1000)) return 0xFF; // 2. 检测引导码高电平部分 start_time = get_timestamp(); while(DL_GPIO_readPins(GPIOA, DL_GPIO_PIN_9) == 1); duration = get_timestamp() - start_time; if(duration < (LEADER_LOW/1000 - TOLERANCE/1000) || duration > (LEADER_LOW/1000 + TOLERANCE/1000)) return 0xFF; // 3. 接收8位数据 for(int i = 0; i < 8; i++) { start_time = get_timestamp(); while(DL_GPIO_readPins(GPIOA, DL_GPIO_PIN_9) == 0); duration = get_timestamp() - start_time; // 检查数据位高电平部分 if(duration < (BIT_HIGH/1000 - TOLERANCE/1000) || duration > (BIT_HIGH/1000 + TOLERANCE/1000)) return 0xFF; start_time = get_timestamp(); while(DL_GPIO_readPins(GPIOA, DL_GPIO_PIN_9) == 1); duration = get_timestamp() - start_time; // 判断逻辑位 if(duration >= (BIT_ONE_LOW/1000 - TOLERANCE/1000) && duration <= (BIT_ONE_LOW/1000 + TOLERANCE/1000)) { data |= (1 << (7 - i)); // 设置逻辑"1" } else if(duration >= (BIT_ZERO_LOW/1000 - TOLERANCE/1000) && duration <= (BIT_ZERO_LOW/1000 + TOLERANCE/1000)) { // 逻辑"0"不需要设置,默认为0 } else { return 0xFF; // 无效时序 } } return data; } /******************** 系统初始化 ********************/ void init_system(void) { // 添加SysTick初始化(1ms中断) DL_SYSTICK_config(32000); // 设置SysTick中断优先级 NVIC_SetPriority(SysTick_IRQn, 3); DL_GPIO_initDigitalInput(DL_GPIO_PIN_9); // 设置 NVIC_SetPriority(SysTick_IRQn, 3); // 启用全局中断 __enable_irq(); // 初始化串口屏 delay_us(2000000); // 等待串口屏启动(2秒) tjc_change_page(TJC_PAGE_MAIN); tjc_set_text(TJC_TEXT_STATUS, "等待红外信号"); tjc_set_text(TJC_TEXT_TIME, "系统启动完成"); tjc_send_cmd("vis b0,1"); // 显示复位按钮 } /******************** 主业务逻辑 ********************/ void security_fsm(void) { // 1. 检测锁定状态 if(retry_count >= MAX_RETRY) { if(get_timestamp() - last_fail_time < LOCK_TIME) { tjc_set_text(TJC_TEXT_STATUS, "锁定中,请稍候"); return; } retry_count = 0; } // 2. 尝试接收数据包 uint8_t rx_code = ir_receive_packet(); if(rx_code == 0xFF) { tjc_set_text(TJC_TEXT_STATUS, "信号接收失败"); tjc_beep(200); return; } // 3. 动态解码验证 if(validate_dynamic_code(rx_code)) { tjc_set_text(TJC_TEXT_STATUS, "认证成功"); tjc_beep(100); delay_us(50000); // 50ms延迟 tjc_beep(100); retry_count = 0; } else { char msg[30]; snprintf(msg, sizeof(msg), "失败(剩余%d次)", MAX_RETRY - retry_count - 1); tjc_set_text(TJC_TEXT_STATUS, msg); tjc_beep(500); retry_count++; last_fail_time = get_timestamp(); } } /******************** 主函数 ********************/ int main(void) { // 系统初始化 - 必须先调用 SYSCFG_DL_init(); // 初始化系统 init_system(); //rx_code =ir_receive_packet(); // 清除中断标志 NVIC_ClearPendingIRQ(UART_0_INST_INT_IRQN); NVIC_EnableIRQ(UART_0_INST_INT_IRQN); char str[50]; uint32_t last_time = 0; uint32_t counter = 0; uint8_t rx_code ; // 添加调试信息 #ifdef DEBUG printf("SystemCoreClock: %lu Hz\n", SystemCoreClock); printf("SysTick LOAD: 0x%08lX\n", SysTick->LOAD); printf("SysTick CTRL: 0x%08lX\n", SysTick->CTRL); #endif while(1) { // 每秒更新显示 if(now_time - last_time >= 1000) { last_time = now_time; counter++; // 更新显示内容 snprintf(str, sizeof(str), "t1.txt=\"运行: %d秒\"", counter); tjc_send_cmd(str); } // 红外信号检测 security_fsm(); // 低功耗等待 __WFI(); } }同样原因
07-06
/********************************************************************************************* * 程序功能:基于51单片机的舵机控制参考程序 * 主要硬件:STC89C52RC单片机最小系统+180度舵机 * 店铺名称:电子爱好者之家 * 店铺网址:http://dianzi.taobao.com * 编辑日期:2022-7-11 **********************************************************************************************/ #include "reg52.h" // 头文件 sbit Sevro_moto_pwm=P2^0; // 舵机信号线(橙色) unsigned char pwm_val = 0;//变量定义 unsigned char push_val = 14;//舵机归中,产生约,1.5MS 信号 void delay1ms(unsigned int k) //延时1ms函数,k等于多少就延时多少ms { unsigned int a,b,c,d; for(d=0;d<k;d++) for(c=1;c>0;c--) for(b=50;b>0;b--) for(a=2;a>0;a--); } /********************************************************************************************** ** TIMER1中断服务子函数产生PWM信号 **********************************************************************************************/ void time1()interrupt 3 using 2 { TH1=(65536-100)/256; //100US定时 TL1=(65536-100)%256; pwm_val++; if(pwm_val<=push_val) Sevro_moto_pwm=1; //PWM信号高电平时间 else Sevro_moto_pwm=0; //PWM信号高电平时间 if(pwm_val>=100) pwm_val=0; } /********************************************************************************************** ** 主函数 **********************************************************************************************/ void main(void) { TMOD=0X10; TH1=(65536-100)/256; //100US定时 TL1=(65536-100)%256; TR1= 1; ET1= 1; EA = 1; push_val=13; //舵机归中,机器执行指令有周期,所以PWM信号有误差 delay1ms(1000); //延时1S让舵机转到其位置,停留一下 while(1) /*无限循环*/ { push_val=4; //舵机向正转约90度,机器执行指令有周期,所以PWM信号有误差 delay1ms(500); //延时500MS让舵机转到其位置 push_val=22; //舵机向反转约90度,机器执行指令有周期,所以PWM信号有误差 delay1ms(500);; //延时500MS让舵机转到其位置 } } /********************************************************************************************** ** END FILE **********************************************************************************************/ 改成msp430f5529
05-27
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值