宏定义

C语言预处理理论-宏定义2

和自甴很熟 提交于 2019-12-02 08:10:31
宏定义2 1、带参宏和带参函数的区别 (1)宏定义是在预处理期间处理的,而函数是在编译期间处理的。这个区别带来的实质差异是:宏定义最终是在调用宏的 地方把宏体原地展开,而函数是在调用函数处跳转到函数中去执行,执行完后再跳转回来。 注:宏定义和函数最大差别就是:宏定义是原地展开,因此没有调用开销;而函数是跳转执行再返回,因此函数有比较大 的调用开销。所以宏定义和函数相比,优势就是没有调用开销,没有传参开销,所以当函数体很短(尤其是只有一句话) 可以用宏定义来替代,这样效率高。 (2)带参宏和带参函数的一个重要差别就是:宏定义不会检查参数的类型,返回值也不会附带类型;而函数有明确的参数类型 和返回值类型。当我们调用函数时编译器会帮我们做参数的静态类型检查,如果编译器发现我们实际传参和参数声明不一样时就会 报错或者报警告。 注:用函数的时候程序员不太用操心类型不匹配,因为编译器会检查,如果不匹配编译器会有提示;用宏的时候程序员必须很注意 实际传参和宏所希望的参数类型一致,否则可能编译不报错,但是运行有误。 总结:宏和函数各有千秋,各有优劣。总的来说,如果代码比较多用函数适合而且不影响效率;但是对于那些只有一两句话的函数开销 就太大了,适合用带参宏。但是用带参宏又有缺点:不检查参数类型。 2、内联函数和inline关键字 (1)内联函数通过在函数定义前加incline关键字实现。 (2

C语言预处理理论

橙三吉。 提交于 2019-12-02 03:39:53
C语言预处理理论 1、从源码到可执行文件的过程 (1)源码.c->(编译)->elf可执行程序 (2)源码.c->(编译)->目标文件.o->(链接)->elf可执行程序 (3)源码.c->(编译)->汇编文件.s->(汇编)->目标文件.o->(链接)-> (4)源码.c->(预处理)->预处理过的.i源文件->(编译)->汇编文件.s->(汇编)->目标文件.o->(链接)->elf可执行程序 2、预处理用预处理器,编译用编译器,汇编用汇编器,链接用链接器,这几个工具再加上一些其他的额外会用到的可用工具, 合起来叫编译工具链。gcc就是一个编译工具链。 3、预处理的意义 (1)编译器本身的主要目的是编译源代码,将C的源代码转化成.S的汇编代码。编译器聚焦核心功能后,就剥离出了一些 非核心的功能到预处理器去了。 (2)预处理帮编译器做一些编译前的杂事。 4、编程中常见的预处理 (1)#include(#include <>和#include""的区别) (2)注释 (3)#if #elif #endif #ifdef (4)宏定义 5、gcc中只预处理不编译的方法 (1)gcc编译时可以给一些参数来做一些设置,譬如gcc xx.c -o xx可以指定可执行程序的名称,譬如gcc xx.c -c -o xx.o 可以指定只编译不链接,也可以生成.o的目标文件。 (2)gcc -E

【走过的弯路】Source Insight 常用配置汇总

拟墨画扇 提交于 2019-12-01 15:23:38
1.删除注释时半个汉字问题(删除一个汉字,汉字没有了,但会多出一个问号?), 方法: ① 将 SuperBackspace.em 复制到 Source Insight安装目录; ② Project→Open Project,打开Base项目; ③ 将复制过去的SuperBackspace.em添加(鼠标直接拖进入)入Base项目; ④ 重启SourceInsight; ⑤ Options→Key Assignments,将Marco: SuperBackspace绑定到BackSpace键; ⑥ Enjoy!! SuperBackspace.em 的源码在博文最后面,复制保存为SuperBackspace.em即可,或者可以在这里直接下载: http://pan.baidu.com/share/link?shareid=101784&uk=3204866771 2. SI对每个字符的宽度不太一致,所以导致内容无法对齐,解决方法: 选上"view --> draft view", 就可以让每个字符的宽度一致了。快捷键是 "Alt + F12",还有字体需要设置成courier(在显示更多字体里面,把它调出来才能在字体中找到) 3.有时候要用块注释,需要用到/**/,但是SI中的数字键上方的/*的键被占用了,需要改回来,同样可以该-+键,还有更多快捷键,比如go to define

C/C++ #define 宏定义

非 Y 不嫁゛ 提交于 2019-12-01 11:55:39
#define命令是C语言中的一个宏定义命令,它用来将 一个标识符 定义为 一个字符串 ,该标识符被称为 宏名 ,被定义的字符串称为 替换文本 。 定义宏的作用一般是用一个 短 的名字代表一个 长 的字符串。 一般形式为: 1)#define 标识符 字符串 这就是已经介绍过的 定义符号常量 。 如:#define PI 3.1415926 2)还可以用#define命令定义 带参数 的宏定义。其定义的一般形式为: #define 宏名(参数表) 字符串 如:#define S(a, b) a*b //定义宏S(矩形面积),a、b为宏的参数 使用的形式如下: area=S(3, 2); 用3、2分别 代替 宏定义中的形式参数a和b,即用3*2代替S(3, 2)。因此赋值语句展开为: area=3*2; 由于C++增加了 内置函数(inline) ,比用带参数的宏定义更方便,因此在C++中基本上已 不再用#define命令定义宏 了,主要用于 条件编译 中。 参考链接: https://blog.csdn.net/zhouqt/article/details/82718409 https://www.jb51.net/article/105807.htm http://c.biancheng.net/cpp/biancheng/view/147.html https://www

宏定义和内存分配

天大地大妈咪最大 提交于 2019-12-01 08:31:16
代码想转换成.exe文件,需要经过几个步骤: 替换 ->为了可读性或方便,使用了一些宏定义;在编译前,会有一个工具将宏定义的符号替换成相应的值; 编译 ->将代码转成二进制文件; 连接 ->代码中可能用到了别人写的程序,连接就是将别人的程序复制一份放到自己的程序中; 1.宏定义 1)无参数的宏定义 无参数的宏定义的一般形式为:# define 标识符 字符序列 例如: 注意: 1、只作字符序列的替换工作,不作任何语法的检查 2、如果宏定义不当,错误要到预处理之后的编译阶段才能发现 2)带参数的宏定义 带参数宏定义:#define 标识符(参数表)字符序列 例如: # define MAX(A,B) ((A) > (B)?(A):(B)) 代码 x= MAX( p, q)将被替换成 y=((p) >(q)?(p):(q) 好处是:如果直接定义一个相同功能的函数,在执行是必须给函数分配内存空间,而宏定义是替换代码,不需要给子函数分配空间; 注意: 1、宏名标识符与左圆括号之间不允许有空白符,应紧接在一起.否则会被当做不带参数的宏括号后面的参数被当做该符号的值 2、宏与函数的区别:函数分配额外的堆栈空间,而宏只是替换. 3、为了避免出错,宏定义中给形参加上括号. 4、末尾不需要分号. 5、define可以替代多行的代码,记得后面加 \ #define MALLOC(n,type)\ (

宏定义与const的区别

陌路散爱 提交于 2019-11-30 20:25:32
(1) 编译器处理方式不同   define宏是在预处理阶段展开。   const常量是编译运行阶段使用。 (2) 类型和安全检查不同   define宏没有类型,不做任何类型检查,仅仅是展开。   const常量有具体的类型,在编译阶段会执行类型检查。 (3) 存储方式不同   define宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存。   const常量会在内存中分配(可以是堆中也可以是栈中)。 (4)const 可以节省空间,避免不必要的内存分配。 例如: #define PI 3.14159 //常量宏 const doulbe Pi=3.14159; //此时并未将Pi放入ROM中 ...... double i=Pi; //此时为Pi分配内存,以后不再分配! double I=PI; //编译期间进行宏替换,分配内存 double j=Pi; //没有内存分配 double J=PI; //再进行宏替换,又一次分配内存! const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而 #define定义的常量在内存中有若干个拷贝。 (5) 提高了效率。 编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量

C++学习笔记之常量篇

点点圈 提交于 2019-11-30 19:08:54
1. 定义成 const 后的常量,程序对其中只能读不能修改。 以下程序是错误的,因为开头就已经固定了常量,便不能再对其进行赋值: #include <iostream> using namespace std; int main() { const double pi; //圆周率的值用pi表示 pi=3.14159265; cout<<"圆周率的近似值是"<<pi<<endl; return 0; } 下面给出正确的赋值方法: #include <iostream> using namespace std; int main() { const double pi=3.141592; //圆周率的值用pi表示 cout<<"圆周率的近似值是"<<pi<<endl; return 0; } 2. 宏定义 #define 和常量 const 的区别 类型和安全检查不同 宏定义是字符替换,没有数据类型的区别,同时这种替换没有类型安全检查,可能产生边际效应等错误; const常量是常量的声明,有类型区别,需要在编译阶段进行类型检查 编译器处理不同 宏定义是一个"编译时"概念,在预处理阶段展开,不能对宏定义进行调试,生命周期结束与编译时期; const常量是一个"运行时"概念,在程序运行使用,类似于一个只读行数据 存储方式不同 宏定义是直接替换,不会分配内存,存储与程序的代码段中;

stm32学习笔记——DMA

邮差的信 提交于 2019-11-30 18:17:31
stm32 学习笔记—— DMA 目的:用 DMA 发送数据到 USART1 并同时点亮 LED 灯,熟悉 DMA 配置过程 配置文件: #include "stm32f10x_dma.h" #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h" #include "stm32f10x_usart.h" 结构体定义: typedef struct { uint32_t DMA_PeripheralBaseAddr; //DMA 传输目标地址 uint32_t DMA_MemoryBaseAddr; //DAM 传输源地址 uint32_t DMA_DIR; //DMA 传输方向 uint32_t DMA_BufferSize; //DMA 传输大小 uint32_t DMA_PeripheralInc; // 外设是否开启地址自增 uint32_t DMA_MemoryInc; // 内存是否开启地址自增 / uint32_t DMA_PeripheralDataSize;// 外设数据单元 uint32_t DMA_MemoryDataSize; // 内存数据单元,与前者须一致 uint32_t DMA_Mode; //DMA 模式,可循环,也可不循环 uint32_t DMA_Priority; //DMA 优先级,多个

ios常用宏定义

大兔子大兔子 提交于 2019-11-29 15:56:13
//十六进制转rgb #define ColorWithHexString(hexString) [UIColor colorWithHexString:hexString] // 获取RGB颜色 #define RGBA(r,g,b,a) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:a] #define RGB(r,g,b) RGBA(r,g,b,1.0f) //字体颜色 #define TITLE_EA_COLOR RGB(51,51,51) #define TITLE_CD_COLOR RGB(34, 34, 34) #define TITLE_AEC_COLOR RGB(153,153,153) #define VIEW_BDA_COLOR RGB(241,241,241) #define SELECT_LINE_Color RGB(216,0,8) #define SELECT_TITLE_Color RGB(58,58,58) #define Button_COLOR1 RGB(51,51,51) #define LINE_COLOR RGB(168,168,168) //颜色 #define ColorHex_333333 ColorWithHexString(@"#333333"

说说编译器是否会对已知结果的运算式做出优化?(老物)

爷,独闯天下 提交于 2019-11-29 11:58:39
有时候我们想优化一些语句,例如: 你会发现,这个 (8 * sizeof(uint32_t)) 不是会每次循环中浪费一次运算的时间吗? 那么针对这个问题我们可以通过宏定义或者静态常数处理,宏定义不用说大家都直接,直接把运算常数结果定义出来就可以了,但是带来的问题不仅是破坏了原有代码的拓展性和可读性,还带来了调试终止条件困难的结果,如果不是高级的IDE可能要到处查看引用才知道终止常数是多少。 那么利用静态常数做处理,则代码改成如下: 你会发现,这不是浪费了一个4字节的静态空间,而且还不是要每次函数进来时进行一次运算才行吗? 如果这样去想就会发现问题了,同时,本文的正题也就出来了,对于一个已知结果的运算式,编译器是否会做出优化呢?答案自然是肯定的,但是为什么呢? 因为,静态化变量如果要初始化的要求是赋予常量,反过来说,如果 (8 * sizeof(uint32_t)) 不是常量肯定不会通过编译,既然编译器知道它是常量,那是不是就意味着它是一个优化的结果? 毕竟已经帮你提前算出结果并视为常量?所以这是不是意味着我们可以放心的使用一个已知结果的运算式作为一个常量来使用呢? 附上一个图来说明问题: 其实可以不用像我写的代码那样把常量存储到变量中,把常量写入一个变量仅仅是为了说明这个问题和方便我调试时看到终止条件值而不是自己推断终止条件(考虑代码可读性)。同时