c语言学习笔记(13)pragma详解,#和##运算符及编译指示字总结
来源:互联网 发布:2017网络最美情歌对唱 编辑:程序博客网 时间:2024/06/01 07:55
摘要:总结了#error,#line的意义和用法,#和##运算符的用法,分析了pragma在控制内存对齐机制时候的用法,总结了struct在内存中的对齐方式,最后用一个面试题加深理解。
一、#error和#warning
#error用于生成一个编译错误消息,并停止编译,该指示字用于指示程序员自己定义的错误信息。
#warning用于生成警告信息,但是不会停止编译。
用法:
#error message
message不需要用双引号。
二、#line
#line用于强制指定新的行号和编译文件名,并对源程序的代码重新编号
用法:
#line number filename(可以不加)
该指示字的本质是重新定义_LINE_和_FILE_
这个有什么作用呢?比如我们在编译的时候,某个部分出错了,因为一个庞大的代码是很多人一起写的,可以使用这个在自己写的代码部分定义为第一行,文件名称改为自己的名称,这样编译出错的时候,就直接显示谁写的代码第几行出错了,然后谁拿回去修改就可以了。
三、#运算符
#运算符用于在预编译期将宏参数转换为字符串,例如:
#defineCONVERS(X) #X
我们在使用:
printf(“%s\n“,CONVERS(while));
printf(“%s\n“,CONVERS(if));
的时候,输出的就是while和if,因为#已经把他们转换成了字符串的形式,也就是”while”和”if”。
四、##运算符
##运算符用于在预编译期粘连两个符号,例如:
#defineNAME(n) name##n
我们在main函数里面,int NAME(1),实际上就是int name1,因为##符号把他们粘连在一起了。
##运算符还可以用来定义结构类型,起到大大简化代码的作用。
五、pragma详解
1.pragma简介
下面将会给出pragma的解释,说实话,看不太懂,有点抽象,用自己的话说,pragma是一种编译指示字,有什么用处呢?配合下面的message使用可以把编译的消息输出到我们的窗口,用来对编译版本进行控制,用法就是pragma message因为有时候一个版本要编译很久,如果编译错了,浪费时间,在编译开始的时候就进行输出,用于控制。
#pragma是编译器指示字,用于指示编译器完成一些特定的动
#pragma所定义的很多指示字是编译器和操作系统特有的
#pragma在不同的编译器间是不可移植的
预处理器将忽略它不认识的#pragma指令
两个不同的编译器可能以两种不同的方式解释同一条#pragma指令
一般用法:
#pragma parameter
注:不同的parameter参数语法和意义各不相同
2.#pragmamessage
message参数在大多数的编译器中都有相似的实现
message参数在编译时输出消息到编译输出窗口中
message可用于代码的版本控制
3.#pragma pack
这个好像很重要,可以控制内存对齐的大小。
那么什么是内存对齐?我们在移植u-boot或者arm裸机的启动代码里面经常看到要设置字节对齐方式,一般是四字节,解释起来就是不同类型的数据在内存中按照一定的规则排列;而
不是顺序的一个接一个的排放,这就是对齐。这句话再解释一下什么意思呢?比如我们申请一个char型数据,在申请一个short类型的,再申请一个int类型的,他们并不是按照从0开始,放在第一,第二,第四个内存位置的,而是按照一定的对齐方式,他们之间存在间隔。
为什么需要内存对齐呢?CPU对内存的读取不是连续的,而是分成块读取的,块的大小只能是1、2、4、8、16字节当读取操作的数据未对齐,则需要两次总线周期来访问内存,因此性能会大打折扣,某些硬件平台只能从规定的地址处取某些特定类型的数据,否则抛出硬件异常。
#pragma pack能够改变编译器的默认对齐方式。
例程如下:
#include<stdio.h> int a; #pragma pack(2)struct TEST1{char c1;short s;char c2;int i; };#pragma pack() #pragma pack(4) struct TEST2{char c1;char c2;short s;int i; };#pragma pack() int main(void){ printf("test1size is:%d\n",sizeof(struct TEST1)); printf("test2size is:%d\n",sizeof(struct TEST2)); printf("asize is:%d\n",sizeof(a)); return0; }运行之后的输出结果:#test1size is:10#test2size is:8#asize is:4
可以看到通过不同的pragma pack指定的对齐方式,结构体的大小是不一样的,我们也可以把两个pack里面的值都改为4,可以看到输出结果如下:
#test1size is:12
#test2size is:8
#a sizeis:4
同样的对齐方式,同样的结构体成员,只是顺序不同,打印出来的大小也不同,为什么呢?下面会解释。
4.struct占用内存大小的机制
第一个成员起始于0偏移处。
每个成员按其类型大小和指定对齐参数n中较小的一个进行对齐。
偏移地址和成员占用大小均需对齐,偏移地址必须是刚才选出来的小的那个数的整数倍,这个很重要。
结构体成员的对齐参数为其所有成员使用的对齐参数的最大值,也就是说加入我们在别的地方使用了整个结构体的大小,那么不是这个结构体所有成员的对其参数的和,而是取那个最大值。
结构体总长度必须为所有对齐参数的整数倍
微软的面试题,例程:
<span style="font-size:18px;">#include <stdio.h> #pragma pack(8) struct S1{ short a; long b;}; struct S2{ char c; struct S1 d; double e;}; #pragma pack() int main(){ struct S2 s2; printf("%d\n", sizeof(struct S1)); printf("%d\n", sizeof(struct S2)); printf("%d\n", (int)&(s2.d) - (int)&(s2.c)); return 0;}</span>
最后输出的结果在linux下运行的结果是8,20,4因为gcc不支持8字节对其,支持4字节对齐方式。在vc下编译运行的结果就是8,24,4.具体过程分析参照上面的总结,和下面的这幅图:
这篇帖子就总结到这里,如有不正确的地方还请指出,大家共同进步!
- c语言学习笔记(13)pragma详解,#和##运算符及编译指示字总结
- 【C语言复习(十一)】#pragma编译指示字相关使用
- 编译指示指令(#pragma)
- C语言sizeof,pragma 和对齐详解
- 学习笔记2-C语言的运算符和程序结构
- C语言学习笔记3-运算符和表达式
- #C语言学习笔记#运算符、表达式和语句
- C语言笔记(运算符及表达式)
- C语言编译指示字#error #warning #line
- C语言学习笔记(运算符)
- C语言_“/”和“%”运算符详解
- 【C语言学习笔记】基础语法及基本运算
- #pragma 指示符
- C语言学习:运算符和表达式
- 学习笔记---C语言运算符规则及数据类型的自动/强制转化规则
- 【C语言学习笔记】进制和位运算
- 【C 语言】编译过程 分析 ( 预处理 | 编译 | 汇编 | 链接 | 宏定义 | 条件编译 | 编译器指示字 )
- 【黑马程序员】C语言学习笔记之第一个C程序及编译运行(一)
- PostgreSQL customize inet_aton, inet_ntoa function in text type like MySQL.
- springMVC配置文件解释(2)
- 【SQL】删除表中重复数据
- 【集训队作业】DGCD
- 为Firefox安装样式
- c语言学习笔记(13)pragma详解,#和##运算符及编译指示字总结
- MFC(一) 程序运行机制编故事
- 针对不等式的定积分计算
- linux shell — 3.linux的档案属性和目录配置(2)
- ssis 面试题
- PostgreSQL Server Encoding sql_ascii attention
- 九度OJ 1003:A+B
- PostgreSQL trigger introduction - 1
- 基于scrapy的开发