VC #define EC(x) L##x 作用说明

本文详细解析了C语言中宏定义的使用技巧,包括连接符##、字符串化操作符#及#@的应用,并通过实例展示了这些操作符如何在宏定义中工作。

#define EC(x) L##x 作用说明

表示L与x连接。
#define Conn(x,y) x##y
#define ToChar(x) #@x
#define ToString(x) #x

x##y表示什么?表示x连接y,举例说:
int  n = Conn(123,456);  结果就是n=123456;
char* str = Conn("asdf", "adf")结果就是 str = "asdfadf";
怎么样,很神奇吧

再来看#@x,其实就是给x加上单引号,结果返回是一个const char。举例说:
char a = ToChar(1);结果就是a='1';
做个越界试验char a = ToChar(123);结果是a='3';
但是如果你的参数超过四个字符,编译器就给给你报错了!error C2015: too many characters in constant   :P

最后看看#x,估计你也明白了,他是给x加双引号
char* str = ToString(123132);就成了str="123132";

## 连接符与# 符

##连接符号由两个井号组成,其功能是在带参数的宏定义中将两个子串(token)联接起来,从而形成一个新的子串。但它不可以是第一个或者最后一个子串。所谓的子串 (token)就是指编译器能够识别的最小语法单元。具体的定义在编译原理里有详尽的解释,但不知道也无所谓。同时值得注意的是#符是把传递过来的参数当成字符串进行替代。下面来看看它们是怎样工作的。这是MSDN上的一个例子。

假设程序中已经定义了这样一个带参数的宏:
#define paster( n ) printf( "token" #n " = %d", token##n )

同时又定义了一个整形变量:
int token9 = 9;

现在在主程序中以下面的方式调用这个宏:
paster( 9 );

那么在编译时,上面的这句话被扩展为:
printf( "token" "9" " = %d", token9 );

注意到在这个例子中,paster(9);中的这个”9”被原封不动的当成了一个字符串,与”token”连接在了一起,从而成为了token9。而#n也被”9”所替代。

可想而知,上面程序运行的结果就是在屏幕上打印出token9=9
---------------------------------------------------------------

#define display(name) printf(""#name"")
int main() {
display(name);
}
====================================
特殊性就在于它是个宏,宏里面处理#号就如LS所说!
处理后就是一个附加的字符串!

但printf(""#name"") ;就不行了!
---------------------------------------------------------------

#define display(name) printf(""#name"")

该定义 字符串化name,
得到结果其实就是 printf("name")
(前后的空字符串拿掉)

这样输出来的自然是 name

从另外一个角度讲,
#是一个连接符号,
参与运算了, 自然不会输出了 ...

另外还有:
#define A(x) T_##x
#define B(x) #@x
#define C(x) #x
我们假设:x=1,则有:
A(1)------)T_1
B(1)------)'1'
C(1)------)"1"

转自:http://blog.21ic.com/user1/1772/archives/2007/44501.html

#是C语言中宏定义里的一个操作符
英文名叫Stringizing Operator
中文名我也不知道
简单说,它的意思就是使用参数被双引号包住
#@是使参数用单引号包住
##是粘结
看MSDN上鸟语写的也太费劲
我就给你举个例子
就比如你这样定义之后
#define print(x) printf(#x)
在程序中写
print(123);
实际上是相当于
printf("123");
就直接输出123
如果
print("123");
就相当于
printf("\"123\"");
就输出"123"
再补充一下
如果
print("\n");
就相当于
printf("\"\\n");
就输出
"\n"


printf的#

C语言中#号和##号的使用

#define display(name) printf(""#name"")
int main() {
display(name);
}
运行结果是name,为什么不是"#name"呢?
---------------------------------------------------------------

#在这里是字符串化的意思
printf(""#name"") 相当于
printf("" "name" "")
---------------------------------------------------------------

The number-sign or "stringizing" operator (#) converts macro parameters (after expansion) to string constants
---------------------------------------------------------------

printf("" #name "") <1>
相当于printf("" "name" "") <2>
而<2>中的第2,3个“中间时空格 等价于("空+name+空')
---------------------------------------------------------------

#include "reg52.h" #include "intrins.h" //-------宏定义--------- #define u8 unsigned char #define u16 unsigned int #define u32 unsigned long #define Cref 2200 //基准电容值(单位pF) #define LCD_DATA P0 //LCD数据口(8位) //-------I/O定义-------- sbit LCD_BUSY = P0^7; //LCD忙信号 sbit LCD_RS = P1^0; //数据/命令选择(数据=1,命令=0) sbit LCD_RW = P1^1; //读/写选择(写=0,读=1) sbit LCD_EN = P1^2; //使能信号 sbit K1_F_LC = P1^3; //F/LC测量选择按钮(自锁),([抬起]=0测LC,[按下]=1测F) sbit K2_L_C = P1^4; //L/C测量选择按钮(自锁)([抬起]=0测C,[按下]=1测L) sbit K3_Eb_Es = P1^6; //电解量程选择按钮(自锁),([抬起]=0低量程,[按下]=1高量程) sbit K4_FLC_EC = P3^6; //FLC或EC(电解电容)测量选择按钮(无锁)(每按一次,翻转一次) sbit K5_Calib = P3^7; //手工校正(清零)按钮(无锁)(消除寄生电容值) sbit Dischg = P1^5; //测量电解电容时的充放电控制端口(=0放电,=1充电) //-------全局变量定义-------- bit FLC_EC_Flag; //测量标志(=0测FLC,=1测电解电容) u8 Measure_Flag; //测量标志(=1测电容,=2测电感,=3测频率,=4测小电解,=5测大电解) u8 Lref; //基准电感值(单位uH)(原作没有) u16 T0_times; //T0中断计数预设值(每50ms一次),测F=20次(1s),测LC=10次(0.5s) u16 Timer0_Num; //T0计数 u16 Timer1_Num; //T1计数 u32 Frequency0; //频率0(未接被测元件时的频率) u32 Frequency1; //频率1(接入被测元件时的频率) u32 Cx; //被测电容 u32 Lx; //被测电感 u32 ECx_H; //被测电解电容() u32 ECx_L; //被测电解电容() //------x的n次方------------ u32 power(u8 x,u8 n) { u8 i; u32 j = 1; if(n == 0) { return 1; } else { for(i=0; i<n; i++) { j *= x; } return j; } } //----延时n毫秒(12M晶振,12T模式,一个指令周期=1us)--- //----1ms=(跳转等3个指令周期+两个空指令)*200---- void Delay_ms(u8 n) { u8 i,j; for(i=0; i<n; i++) { for(j=0; j<200; j++) { _nop_(); _nop_(); } } } //------LCD1602读忙标志位------ void Check_busy(void) { do { LCD_EN=0; LCD_RS=0; LCD_RW=1; LCD_DATA=0xFF; LCD_EN=1; } while(LCD_BUSY==1); LCD_EN=0; } //------LCD1602写指令------ void Write_Command(u8 cmd) { Check_busy(); LCD_RS=0; LCD_RW=0; LCD_DATA=cmd; LCD_EN=0; LCD_EN=1; LCD_EN=0; } //------LCD1602写数据------ void Write_Data(u8 dat) { Check_busy(); LCD_RS=1; LCD_RW=0; LCD_DATA=dat; LCD_EN=0; //机器周期小于1us时,须加延时 LCD_EN=1; LCD_EN=0; } //-----LCD1602写字符串------ //---x=列(0~15); y=行(0,1) //---从指定的位置开始写,直到超出屏幕显示 void LCD_Write_String(u8 y,u8 x,u8 *Data) { if(y==0) //第一行 { if(x<16) { Write_Command(0x80+x); //0x80 + 第一行起始地址 for(; x<16&&*Data!='\0'; x++) //'\0'字符串结束标志 { Write_Data(*(Data++)); } } } if(y==1) //第二行 { if(x<16) { Write_Command(0xc0+x); //0xc0 + 第二行起始地址 for(; x<16&&*Data!='\0'; x++) //'\0'字符串结束标志 { Write_Data(*(Data++)); } } } } //------LCD1602写长整型数据------ //x=列(0~15); y=行(0,1);截取长整型后length个数字显示在指定位置(全显示length=10) //注意此函数不支持换行,起始列+length>15时后面的显示不出来,仅能单行显示 void LCD_Write_Long(u8 y,u8 x,u8 length,u32 Data) { u8 i,k; if(length>10) { length = 10; } if(length<10) { Data = Data%power(10,length); } if(y==0) //第一行 { Write_Command(0x80+x); //0x80 + 第一行起始地址 for(i=0; i<length; i++) { k = (u8)(Data/power(10,length-1-i)); Data = Data%power(10,length-1-i); Write_Data(k+0x30); } } if(y==1) //第二行 { Write_Command(0xc0+x); //0xc0 + 第二行起始地址 for(i=0; i<length; i++) { k = (u8)(Data/power(10,length-1-i)); Data = Data%power(10,length-1-i); Write_Data(k+0x30); } } } //------LCD1602写长整型数据,可以指定小数点后位数------- //x=列(0~15); y=行(0,1);截取长整型后length个数字显示在指定位置(全显示length=10) //注意此函数不支持换行,起始列+length>15时后面的显示不出来,仅能单行显示 //pot:小数点后显示几个数字 例:1234567 pot=2时显示为12345.67 void LCD_Write_LongPoint(u8 y,u8 x,u8 length,u8 pot,u32 Data) { u8 i,j,k; if(length>10) { length = 10; } if(length<10) { Data = Data%power(10,length); } if(y==0) //第一行 { j=0; Write_Command(0x80+x); //0x80 + 第一行起始地址 for(i=0; i<=length; i++) { if(i==(length-pot)) { Write_Data(0x2e); //小数点 Write_Command(0x80+x+i+1); } else { k = (u8)(Data/power(10,length-1-j)); Data = Data%power(10,length-1-j); Write_Data(k+0x30); j++; } } } if(y==1) //第二行 { j=0; Write_Command(0xc0+x); //0xc0 + 第二行起始地址 for(i=0; i<=length; i++) { if(i==(length-pot)) { Write_Data(0x2e); //小数点 Write_Command(0xc0+x+i+1); } else { k = (u8)(Data/power(10,length-1-j)); Data = Data%power(10,length-1-j); Write_Data(k+0x30); j++; } } } } //------LCD1602清屏--------- void LCD_Clear(void) { Write_Command(0x01); } //------LCD1602初始化----- void LCD1602_Init(void) { Delay_ms(15); Write_Command(0x38); //16x2显示,8位数据 Write_Command(0x0c); //开显示 Write_Command(0x06); //AC自动加1,字符依次向后写 LCD_Clear(); } //------判断测量类型------- void Get_Measure_Flag(void) { if(FLC_EC_Flag==0) //测FLC按键选择标志位 { if(K1_F_LC==1) { Measure_Flag = 3; //测频率 T0_times = 20; //T0定时1s } else { if(K2_L_C==0) { Measure_Flag = 1; //测电容 } else { Measure_Flag = 2; } T0_times = 10; //T0定时0.5s } } else { TR0 = 0; //关闭测频率(含LC)功能 ET0 = 0; if(K3_Eb_Es==0) { Measure_Flag = 4; //测小电解 } else { Measure_Flag = 5; //测大电解 } } } //------测试(F/L/C)初始化(T0,T1初始化)------ void MeasureFLC_init(void) { Timer0_Num = 0; Timer1_Num = 0; TMOD = 0x51; //T0作定时器,T1作计数器 TH0 = 0x3c; //T0初值高8位(定时50ms) TL0 = 0xb0; //T0初值低8位 TH1 = 0x3c; //T1初值高8位(计数50000次) TL1 = 0xb0; //T1初值低8位 TR0 = 1; //T0开 TR1 = 1; //T1开 ET0 = 1; //T0中断开 ET1 = 1; //T1中断开 EA = 1; //总中断开 } //--------计算L/C值-------- void LC_Calculate(void) { float mes; mes = (float)Frequency0/(float)Frequency1; //频率比 mes *= mes; //平方值 if(mes < 1) //取绝对值 { mes = 1 - mes; } else { mes -= 1; } Cx = 100 * mes * Cref; //计算被测电容值(精确到0.1pF) if((Cx%10) >= 5) //四舍五入 { Cx = Cx/10 + 1; } else { Cx = Cx/10; } Lx = mes * Lref * 1000; //计算被测电感值(精确到0.01uH) if((Lx%10) >= 5) //四舍五入 { Lx = Lx/10 + 1; } else { Lx = Lx/10; } if(Frequency1<50) //防止不接入电感时显示溢出值 { Lx = 0; } } //----自动校正(清除寄生电容值)------- void Auto_Calib(void) { u8 i; if((K1_F_LC != 0) || (K2_L_C != 0)) //判断K1,K2的初始位置 { LCD_Clear(); LCD_Write_String(0,0,"Auto Calib fail!"); if((K1_F_LC == 1) && (K2_L_C == 1)) { LCD_Write_String(1,0,"Need up K1 & K2 "); } else { if(K1_F_LC == 1) { LCD_Write_String(1,0," Need up K1 "); } else { LCD_Write_String(1,0," Need up K2 "); } } while((K1_F_LC == 1) || (K2_L_C == 1)); //等待K1,K2的准确初始位置 for(i=0; i<20; i++) { Delay_ms(75); //延时1.5秒,消抖. } } LC_Calculate(); Delay_ms(150); Lref = (Cx/Cref + 1) * 100; //计算基准电感值(单位uH) Frequency0 = Frequency1; } //-------按键读取-------- void Get_Key(void) { if(K4_FLC_EC == 0) //如果=0(按钮按下) { Delay_ms(50); if(K4_FLC_EC == 0) { FLC_EC_Flag = ~FLC_EC_Flag; //测量标志取反 if(FLC_EC_Flag == 0) //如果=0,是测FLC { EX0 = 0; //关闭测电解电容的功能(外部中断0关) MeasureFLC_init(); //测试(F/L/C)初始化(T0,T1初始化) } else //否则,是测量电解电容. { TR0 = 0; //T0关 ET0 = 0; //T0中断关 } } } if(K5_Calib == 0) //如果=0(按钮按下)(手工校正) { Delay_ms(50); //延时50sm,消抖 if(K5_Calib == 0) { if((K1_F_LC == 0) && (K2_L_C == 0)) //如果K1,K2处于测量电容位置 { Frequency0 = Frequency1; } } } } //-------测试电解电容初始化(T0,T1及外部中断初始化)------- void MeasureElec_init(void) { u8 i; ECx_H = 0; ECx_L = 0; TR1 = 0; ET1 = 0; EX0 = 0; //关外部中断 Dischg = 0; //放电 Delay_ms(180); Delay_ms(200); Dischg = 1; //充电 Timer1_Num = 0; TMOD = 0x11; //T0,T1都作定时器 TH1 = 0x3c; //T1初值高8位(定时50ms) TL1 = 0xb0; //T1初值低8位 TR1 = 1; //T1开 ET1 = 1; //T1中断开 IT0 = 1; //下降沿触发 EX0 = 1; //外部中断开 EA = 1; //总中断开 for(i=0; i<65; i++) //延时1.3s,等待测量 { Delay_ms(20); if(K4_FLC_EC == 0) //如果测量期间K4键按下 { Delay_ms(20); if(K4_FLC_EC == 0) { break; //中止 } } } EX0 = 0; //外部中断关 Dischg = 0; //放电 } //--------定时器0中断处理--------- void Timer0_interrupt(void) interrupt 1 { TH0 = 0x3c; //重装载T0初值高8位(定时50ms) TL0 = 0xb0; //重装载T0初值低8位 Timer0_Num++; //T0计次累加 if(Timer0_Num >= T0_times) //如果T0计次数=T0预设值(测F=20(1s),测LC=10(0.5s)) { TR0 = 0; //T0关 TF0 = 0; //T0溢出标志清零 TR1 = 0; //T1关 TF1 = 0; //T1溢出标志清零 Frequency1 = 50000*Timer1_Num + ((u16)((TH1<<8)+TL1)-0x3cb0); //计算频率值(Frequency1) Timer0_Num = 0; //T0计次清零 Timer1_Num = 0; //T1计次清零 TH0 = 0x3c; //重装载T0初值高8位(定时50ms) TL0 = 0xb0; //重装载T0初值低8位 TH1 = 0x3c; //重装载T1初值高8位(计数50000次) TL1 = 0xb0; //重装载T1初值低8位 TR0 = 1; //T0开 TR1 = 1; //T1开 } } //------定时器1中断处理------- void Timer1_interrupt(void) interrupt 3 { TH1 = 0x3c; //重装载T1初值高8位(定时50ms,或计数50000次) TL1 = 0xb0; //重装载T1初值低8位 Timer1_Num++; //T1计次累加 } //-------外部INT0中断处理-------- void INT0_Interrupt(void) interrupt 0 { if(Measure_Flag==4) { ECx_L = (50000*Timer1_Num + ((u16)((TH1<<8)+TL1)-0x3cb0))*100/2000; //计算低容量电解电容值(精确到0.01uF) if((ECx_L-2)>=0) { ECx_L -= 2; //修正误差 } } if(Measure_Flag==5) { ECx_H = (50000*Timer1_Num + ((u16)((TH1<<8)+TL1)-0x3cb0))*10/100; //计算高容量电解电容值(精确到0.1uF) if((ECx_H-4)>=0) { ECx_H -= 4; //修正误差 } } } //----------- void Main(void) { u8 i; u8 clear; //清屏标志位,如果功能转换则需要清屏 Measure_Flag = 0; FLC_EC_Flag = 0; //开机默认测FLC T0_times = 10; Timer0_Num = 0; Timer1_Num = 0; Frequency0 = 169500; //基准频率的一半(基准频率是:当L=100uH,C=2200pF时的频率,=339000Hz) Frequency1 = 0; LCD1602_Init(); MeasureFLC_init(); LCD_Write_String(0,0," L.C.F Meter "); LCD_Write_String(1,0," 2015-08-01 "); for(i=0; i<20; i++) { Delay_ms(150); //开机画面显示3秒 } Auto_Calib(); while(1) { Get_Key(); //按键扫描 Delay_ms(70); //该延时使按键切换稳定 clear = Measure_Flag; //读测量类型标志及清屏 Get_Measure_Flag(); //获取测量类型标志 if(clear != Measure_Flag) { LCD_Clear(); } switch(Measure_Flag) //根据测量标志计算并显示 { case 1: //测电容 { LC_Calculate(); LCD_Write_String(0,0,"Cx= "); LCD_Write_LongPoint(0,4,8,1,Cx); LCD_Write_String(0,13," pF"); LCD_Write_String(1,0,"freq= "); LCD_Write_Long(1,6,6,Frequency1*2); LCD_Write_String(1,13," Hz"); break; } case 2: //测电感 { LC_Calculate(); LCD_Write_String(0,0,"Lx= "); LCD_Write_LongPoint(0,4,8,2,Lx); LCD_Write_String(0,13," uH"); LCD_Write_String(1,0,"freq= "); LCD_Write_Long(1,6,6,Frequency1*2); LCD_Write_String(1,13," Hz"); break; } case 3: //测频率 { LCD_Write_String(0,0," Meas_Freq "); LCD_Write_String(1,0,"Freq= "); if(Frequency1<40) //如果被测频率小于40Hz { Frequency1=0; //显示零 } LCD_Write_Long(1,6,6,Frequency1); LCD_Write_String(1,13," Hz"); break; } case 4: //测小电解 { LCD_Write_String(0,0,"0.47uF<CEx<600uF"); LCD_Write_String(1,0,"CEx= "); LCD_Write_String(1,14,"uF"); LCD_Write_LongPoint(1,6,5,2,ECx_L); MeasureElec_init(); break; } case 5: //测大电解 { LCD_Write_String(0,0,"220uF< CEx <12mF"); LCD_Write_String(1,0,"CEx= "); LCD_Write_String(1,14,"uF"); LCD_Write_LongPoint(1,6,6,1,ECx_H); MeasureElec_init(); break; } default: break; } } } 请分析上述代码中的电感电容计算原理
最新发布
11-30
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值