C语言中数据类型的使用
紫金洪飞发送站(Fri 2007年11月2日211925)
1,以防止头文件被重复包含。
#ifndef COMDEF_H
#定义COMDEF_H
头文件内容
#endif
2.重新定义一些类型,防止不同平台和编译器造成的类型字节数。
区别,便于移植。
typedef无符号字符布尔值;布尔值类型。
typedef无符号长整型uint32无符号32位值
typedef无符号短整型uint 16;无符号16位值
typedef无符号字符uint8无符号8位值
typedef有符号long int int32带符号的32位值
typedef有符号短整型16;带符号的16位值
typedef有符号字符int8带符号的8位值
以下不推荐。
typedef无符号字符字节;无符号8位值类型。
typedef无符号短词;无符号16位值类型。
typedef无符号长dword无符号32位值类型。
typedef无符号字符uint 1;无符号8位值类型。
typedef无符号短整型uint2无符号16位值类型。
typedef无符号长整型uint4无符号32位值类型。
typedef有符号字符int 1;有符号8位值类型。
typedef有符号短整型2;有符号16位值类型。
typedef long int int4有符号32位值类型。
typedef有符号长整型Sint 31;带符号的32位值
typedef有符号短Sint 15;带符号的16位值
typedef有符号字符sint7带符号的8位值
3、在指定地址获取一个字节或字。
#定义MEM_B( x)(((字节)(x)))
#定义MEM_W( x ) ( ( (word ) (x)))
4.求最大值和最小值。
#定义MAX( x,y ) ( ((x) (y)) (x) (y))
#定义MIN( x,y ) ( ((x) (y)) (x) (y))
5、获取结构中某个字段的偏移量。
#定义FPOS(类型,字段)
lint -e545((类型)0)-字段)lint +e545
6、获取一个结构中字段占用的字节数。
#define FSIZ( type,field)sizeof((type)0)-field)
7.根据LSB格式将两个字节转换成一个字。
# define FLIPW(ray)((((word)(ray)[0])256)+(ray)[1])
8.根据LSB格式将一个字转换成两个字节。
#定义FLOPW(射线,val)
(ray)[0]=((val)256);
(ray)[1]=((val)& amp;0xFF)
9、得到一个变量的地址(字宽)。
# define B _ PTR(var)((byte)(void)& amp;(var))
# define W _ PTR(var)((word)(void)& amp;(var))
10,获取一个字的高低字节。
#define WORD_LO(xxx)((字节)((字)(XXX)& amp;255))
#定义WORD_HI(xxx)((字节)((word)(xxx) 8))
11,返回大于x的8的最近倍数。
#定义RND8( x ) ((((x) + 7) 8 ) 8)
12,将一个字母转换成大写。
#定义up case(c)(((c)= " a " & amp;& amp(c)= " z ")((c)-0x 20)(c))
13,判断该字符是否为数值为10的数字。
# define DECCHK(c)((c)= " 0 " & amp;& amp(c)=“9”)
14,判断该字符是否为数值为16的数字。
# define hex chk(c)(((c)= " 0 " & amp;& amp(c)=“9”)
((c)= " A " & amp;& amp(c)=“F”)
((c)= " a " & amp;& amp(c)= " f "))
15,一种防止溢出的方法
# define INC _ SAT(val)(val =((val)+1(val))(val)+1(val))
16,返回数组元素的个数。
# define ARR _ SIZE(a)(sizeof((a))sizeof((a[0]))
17,返回值mod _ by _ power _ of _ two (x,n) = x% (2 n),带无符号数的尾部。
#define MOD_BY_POWER_OF_TWO( val,MOD_BY)
((dword)(val)amp;(dword)((mod_by)-1))
18,存储空间中IO空间映射的结构的I/O处理。
#定义inp(端口) (((易失字节)(端口)))
#定义inpw(port)(((volatile word)(port)))
#定义inpdw(port)(((volatile dword)(port)))
#define outp(port,val)(((volatile byte)(port))=((byte)(val)))
#define outpw(port,val)(((volatile word)(port))=((word)(val)))
#define outpdw(port,val)(((volatile dword)(port))=((dword)(val)))
[2005年9月9日添加]
19,用一些宏跟踪调试。
标准描述了五个预定义的宏名。它们是:
_ L I N E _
_ F I L E _
_ D A T E _
_ T I M E _
_ S T D C _
如果编译不标准,可能只支持上述几个宏名,或者根本不支持。记得化妆
翻译程序
也可以提供其他预定义的宏名。
_ L I N E _和_ F I L E _宏指令已经在关于# l i n e的部分讨论过,这里也讨论。
在其他宏名上。
E _ macro指令中的_ D包含一个月、日、年形式的字符串,表示源文件被翻译成代码的日期。
句号。
源代码被翻译成目标代码的时间作为一个字符串包含在_ T I M E _中。字符串形式为小时:分钟:
秒
如果实现是标准的,macro _ S T D C _包含十进制常数1。如果它包含任何其他
数字,实现是非标准的。您可以定义宏,例如
定义_DEBUG时,输出数据信息和文件所在的行。
#ifdef _DEBUG
#define DEBUGMSG(消息,日期)
printf(msg);printf("%d%d%d ",日期,_LINE_,_FILE_)
#否则
#define DEBUGMSG(消息,日期)
#endif
20、阻止宏定义被使用是错误的。
用括号括起来。
例如:#define ADD(a,b) (a+b)
使用do{}while(0)语句包含多个语句以防止出错。
比如:#difne DO(a,b)a+b;
a++;
应用时:如果(...)
DO(a,b);一个错误
其他
解决方案#difne DO(a,b)DO { a+b;
a++;}while(0)
宏中#和# #的用法
一.一般用法
我们使用#将宏参数转换成一个字符串,使用# #将两个宏参数粘贴在一起。
使用
#includecstdio
# include限制
使用命名空间std
#定义字符串#s
#定义CONS(a,b) int(a##e##b)
int main()
{
printf(STR(vck));输出字符串vck
printf(%dn,CONS(2,3));2e3产量2000
返回0;
}
第二,当宏参数是另一个宏时。
应该注意的是,在宏定义中使用' # '或' # # '的地方,宏参数将不会扩展。
1,而不是“#”和“# #”
#定义TOW (2)
#定义MUL(a,b) (ab)
printf(%d%d=%dn,TOW,TOW,MUL(TOW,TOW));
该行中的宏将扩展为:
printf(%d%d=%dn,(2),(2),(2)(2));
MUL中的参数TOW将扩展为(2)。
2、当有“#”或“# #”时
#定义一个(2)
#定义字符串#s
#定义CONS(a,b) int(a##e##b)
printf(int max %sn,STR(INT _ MAX));INT _ MAX #包含限制
这条线路将扩展到:
printf(int max %sn,INT _ MAX);
printf(%sn,CONS(A,A));编译错误
这一行是:
printf(%sn,int(AeA));
INT_MAX和a都不会展开,但是这个问题的解决方法很简单。再加一层。
在之间转换宏。
添加这个宏的目的是扩展这一层所有宏的所有参数,那么转换宏中的哪一个
一个宏(_STR)可以得到正确的宏参数。
#定义一个(2)
# define _ STR # s
#定义字符串_字符串转换宏
#define _CONS(a,b) int(a##e##b)
#定义CONS(a,b) _CONS(a,b)变换宏
printf(int max %sn,STR(INT _ MAX));Int _ max,Int类型的最大值,为
变量# includeclimates
输出为int max 0x7fffffff。
Str (int _ max)-_ str (0x7fffffff)然后转换成字符串;
printf(%dn,CONS(A,A));
输出是:200
CONS(A,A) - _CONS((2),(2)) - int((2)e(2))
三。“#”和“# #”的一些特殊应用
1.合并匿名变量名
# define _ _ _ anonymous 1(type,var,line) type var##line
#define __ANONYMOUS0(type,line)_ANONYMOUS 1(type,_ anonymous,
线)
# define ANONYMOUS(type)_ _ ANONYMOUS 0(type,__LINE__)
例如:ANONYMOUS(static int);即静态int _ anonymous7070表示这条线。
号码;
第一层:匿名(static int);- __ANONYMOUS0(static int,
_ _ LINE _ _);
二楼:-_ _ anonymous 1 (static int,_ anonymous,70);
第三层:-static int _ anonymous 70;
即一次只能解锁当前层的宏,所以__LINE__可以在第二层解锁;
2.填充结构
#定义填充(a) {a,#a}
枚举IDD{OPEN,CLOSE}。
typedef结构消息{
IDD id
const char消息;
} MSG
MSG _msg[] = {FILL(OPEN),FILL(CLOSE)};
相当于:
MSG _ MSG[]= { {打开,打开},
{CLOSE,CLOSE } }
3.记录文件名
#define _GET_FILE_NAME(f) #f
#define获取文件名(f)_获取文件名(f)
静态字符文件名[] =获取文件名(__文件_ _);
4.获取对应于数字类型的stringbuffer大小。
# define _ TYPE _ BUF _ SIZE(TYPE)SIZE of # TYPE
# define TYPE _ BUF _ SIZE(TYPE)_ TYPE _ BUF _ SIZE(TYPE)
char BUF[TYPE _ BUF _ SIZE(INT _ MAX)];
-char BUF[_ TYPE _ BUF _ SIZE(0x 7 fffffff)];
-char buf[sizeof 0x 7 fffffff];
这相当于:
char buf[11];
语言中如何使用C(和C++)中的宏,属于编译器预处理的范畴。
它属于编译时(不是运行时)的概念。以下是对常见宏使用问题的简单描述。
总结一下。
关于#和# #
在C语言的宏中,#的作用是把它后面的宏参数串起来。
(Stringfication),简单来说就是指它所引用的宏变量被替换后是左右的。
给每一个都加上双引号。例如,下面代码中的宏:
#define WARN_IF(EXP)
do{ if (EXP)
fprintf(stderr,Warning # expn);}
while(0)
那么在实际使用中就会出现以下替换过程:
WARN _ IF(divider = = 0);
被替换为
做{
if(分频器== 0)
fprintf(stderr,警告分频器= = 0n);
} while(0);
每当分频器为0时,这将在标准错误流上输出一条提示消息。
而# #称为连接器,用于将两个令牌连接成一个令牌。
注意,这里连接的对象是一个令牌,不一定是宏变量。比如你要做一道菜。
由单个命令名和函数指针组成的结构数组,希望函数名和菜单项被命名。
名字之间有一种直观的关系。那么下面这段代码就很实用了:
结构命令
{
字符名称;
void(函数)(void);
};
#定义命令(名称){名称,名称# # _命令}
然后,您可以使用一些预定义的命令轻松地初始化一个。
一组命令结构:
结构命令命令[] = {
命令(退出)、
命令(帮助),
...
}
命令宏在这里充当代码生成器,可以在一定程度上减少。
代码密度也可以间接减少因粗心导致的错误。我们也可以连接n个符号。
N+1令牌,此功能在#符号中也不可用。例如:
#定义LINK_MULTIPLE(a,b,c,d) a##_##b##_##c##_##d
typedef结构_记录_类型
LINK_MULTIPLE(姓名、公司、职位、薪资);
在这里,这种说法将扩展到:
typedef结构_记录_类型
姓名_公司_职位_薪资;
关于...的使用...
...在C宏中称为Variadic宏,意思是可变参数宏。例如:
#定义myprintf(templt,...)
fprintf(stderr,templt,__VA_ARGS__)
或者
#define myprintf(templt,args...)
fprintf(标准错误,临时,参数)
由于第一个宏没有参数名,我们使用默认的宏__VA_ARGS__来替换它。顺序
在这两个宏中,我们显式地将参数命名为args,因此我们可以在宏定义中使用args。
我改变主意了。和C语言中的stdcall一样,变量参数必须列为参数表中最重要的一项。
现在。当我们在上面的宏中只能提供第一个参数templt时,C标准要求我们写。
程:
myprintf(templt,);
的形式。此时的替换过程是:
myprintf(错误!n,);
替换为:
fprintf(stderr,错误!n,);
这是一个语法错误,无法正常编译。这个问题一般有两种解决方案。首先,GNU
CPP提供的解决方案允许将上述宏调用写成:
myprintf(templt);
它将被替换为:
fprintf(stderr,错误!n,);
显然,这里仍然会有编译错误(除了这个例子之外,在某些情况下不会有编译错误)
不对)。除了这个方法,c99和GNU CPP都支持以下宏定义方法:
#定义myprintf(templt,...)fprintf(stderr,templt,
##__VAR_ARGS__)
此时# #作为连接符号的作用是,当__VAR_ARGS__为空时,在消除之前。
表面上的逗号。那么此时的翻译过程如下:
myprintf(templt);
转换成:
fprintf(stderr,templt);
这样,如果templt合法,就不会出现编译错误。这里有一些易于使用的宏。
哪里出了问题,如何正确使用。
错误嵌套-错误嵌套
宏的定义不一定要有完整的、成对的括号,但是为了避免错误,提高可读性,
最好避免这样的使用。
由运算符优先级引起的问题-运算符优先级问题
因为宏只是一个简单的替换,如果宏的参数是复合结构,那么替换后就有可能了。
因为每个参数之间的运算符优先级高于单个参数内各部分之间的交互
运算符优先,如果我们不用括号保护每个宏参数,可能会产生意想不到的结果。
情况。例如:
# define cell _ div(x,y) (x + y - 1) y
因此
a = ceil _ div(b & amp;c,sizeof(int));
将被转换为:
a =(b & amp;c+sizeof(int)-1)sizeof(int);
因为+-优先于&;优先级,那么上面的公式是等价的。
于:
a =(b & amp;(c+sizeof(int)-1))sizeof(int);
这显然不是打电话人的初衷。为了避免这种情况,你应该多写些括号:
#define ceil_div(x,y) (((x) + (y) - 1) (y))
消除多余的分号-分号吞咽
通常情况下,为了让类似函数的宏表面上看起来像普通的C语言调用。
同样,我们通常在宏后面加一个分号,比如下面这个带参数的宏:
MY _ MACRO(x);
但如果是以下情况:
#定义我的宏(x) {
行1
第二行
第3行}
…
if(条件())
MY _ MACRO(a);
其他
{...}
由于多了一个分号,这将导致编译错误。为了避免这种情况
MY _ MACRO(x);这种写法,我们需要把宏定义成这样的形式:
#define MY_MACRO(x) do {
行1
第二行
第3行} while(0)
所以只要你保证一直用分号,就不会有什么问题。
副作用的复制
这里的副作用意味着宏在扩展时可能会多次评估其参数。
(也就是取值),但是如果这个宏参数是一个函数,可能会被调用很多次。
从而达到不一致的结果,甚至会出现更严重的错误。例如:
#定义min(X,Y) ((X) (Y) (Y) (X))
...
c = min(a,foo(b));
这时foo()函数被调用了两次。为了解决这个潜在的问题,我们应该这样写
宏min(X,Y):
#定义最小值(X,Y) ({
type of(X)X _ =(X);
type of(Y)Y _ =(Y);
(x _ y _)x _ y _;})
({...})是返回几个内部语句最后一个的值,也允许内部声明。
变量(因为它通过大括号形成局部范围)。
-
51e小2为它,513小28为它。
在linux中,我喜欢男人,但实际上,我不是。
最强的递归GNU不是Unix。
我从地狱回来了
眼泪仍留在天堂。
,siiiiiiiiiiiiiiiiiiiiiisssiis 2x 9 gaaaaaaaa & amp;gggh 3x 22552252555222555555555552 r