宏定义

关于C语言中的连接符的用法 # ## macro stringize

蓝咒 提交于 2020-05-02 10:51:35
首先面向需求,小工程、代码不多、版本还挺多... 打算用宏控制开关选项、然后通过一长串 #if #elif ... #endif 来控制生成版本号、而且还要根据兼容性跟细小变更做三级版本号.... 所以就需要一个版本号拼接、明显,应该是编译期能做完的事情。 --------需求完毕-------- C语言宏定义应该是可完成的、在代码执行期间更加是没问题的。 虽然用string.h也可以完成拼接。 不舒服斯基... 初步查找 使用 # 和##,可以完成、进一步查找发现有个#@ 是什么鬼... 部分编译器不支持 经过初步试用# 会直接把传递进来的macro直接变成string,#@理论上是实现我需要的功能,然而并不支持 ---------------神奇的分割线------------------------- 进一步查找stringize site:gcc.gnu.org 找到页面 3.4 Stringification https://gcc.gnu.org/onlinedocs/cpp/Stringification.html 鉴于是blog,就不贴原文了,又需要的自己去看。 结论: If you want to stringify the result of expansion of a macro argument, you have to use two levels of

typedef重复定义 和 error: ‘long long long’ is too long for GCC

大兔子大兔子 提交于 2020-04-07 15:10:35
今天发现一个很有意思的编译问题,然后在Stack Overflow上也有看到类似的。就是出现了 long long long 类型错误提示 错误提示如下: /home/yejy/algorithm_and_data_structure/main.cpp:50:17: error: ‘long long long’ is too long for GCC #define INT64 long long ^ 顾名思义,一个long占4个字节,两个就是8字节,总共64位,等于系统是64位的,如果你使用3个long那就96位了,那肯定会有问题,正常情况下也没人会定义三个long。 ``` #define INT64 long long ``` 然后看代码出错的地方,就是一个宏定义,怎么会出现问题呢? 然后仔细看了一下代码发现是 链接外部库 导致的,工程 A 链接了 B_lib.so 和 C_lib.so 两个动态库, 然后 B 中用宏定义了 long long , C 中使用typedef重新命名了 long long,顺序刚好是宏定义在前,等价于下面两句代码: ``` #define INT64 long long typedef long long INT64; <p style="font-size: 15px; text-indent:2em; letter-spacing:1px

【华为云技术分享】容易造成单片机内存溢出的几个陷阱

放肆的年华 提交于 2020-03-19 17:39:52
【摘要】 关于程序变量和内存分配,都是需要我们时刻关注的问题。我相信有不少人在这块犯过很多的错误,也可能说明我们基础不够扎实,编写程序的习惯也不够好。 总结一下关于程序的变量和内存方面的概念,虽然是属于C语言方面非常基础的知识,但是工作中一不小心还是会发生一些内存泄漏、内存溢出之类的问题。所以自己对这块的理解也还远远不够。在这总结一下关于这方面的知识点,用来互相学习,更用来提醒自己,并作为自己的一个经验总结。 总结一下关于程序的变量,和内存方面的概念,虽然是属于C语言方面非常基础的知识,但是工作中一不小心还是会发生一些内存泄漏、内存溢出之类的问题。所以自己对这块的理解也还远远不够。在这总结一下关于这方面的知识点,用来互相学习,更用来提醒自己,并作为自己的一个经验总结。 我们知道我们的程序一般是储存在flash里面的,但是运行的时候是在内存(RAM)里运行的,我们的程序一般有这么几个部分组成:宏定义、变量、常量、动态区、程序代码。 我们通过下面这个Demo程序来了解一下程序在运行的时候,这些部分大概都在内存中的哪些地方。 1 #define OFF 0x00 //宏定义不占用内存空间,宏在预处理阶段会被替换掉,执行文件中并不存在宏定义. 2 float Num = 3.14; //全局变量,存在于“变量区” 3 char* str = NULL; //全局变量,存在于“变量区” 4

宏常量,宏替换,const常量

徘徊边缘 提交于 2020-03-14 03:59:36
(1)宏常量也称为符号常量,是指用一个标识符号来表示的常量,宏常量是由宏定义编译预处理命令来定义的,宏定义的一般形式:#define 标识符 字符串 宏定义中的标识符被称为宏名,将程序中出现的宏名替换成字符串的过程称为宏替换,宏替换时是不做任何语法检查的,因此,只有在对已经被宏展开后的源程序进行编译时才会发现语法错误 (2)const常量:使用宏常量的最大问题是,宏常量没有数据类型。那么是否可以声明具有某种数据类型的常量呢?这就是const常量 const常量被编译器放在只读存储区,不允许在程序中改变其值,因此const常量只能在定义时赋初值。 来源: https://www.cnblogs.com/ACPIE-liusiqi/p/8877710.html

20180318 代码错题(4)

陌路散爱 提交于 2020-03-07 11:09:37
下面程序的输出结果是__________。 1 2 3 4 5 6 7 #include < iostream.h> #define SQR(A) A*A void main() { int x=6,y=3,z=2; x/=SQR(y+z)/SQR(y+z); cout< < x< < endl; } 5 6 1 0答案 D  错选 B 宏定义是一个很看重括号的东西 1.#define f(x) x*x 这里f(x+y) 就会被翻译成x+y*x+y 为什么,因为你没有添加括号啊宏定义只是简单的替换不会替你加括号 2.#define f(x) (x)*(x) 这里f(x+y) 就会翻译成(x+y)*(x+y) 就是这么回事 回到题上 上述式子等价为 x/=y+z*y+z/y+z*y+z,再加上/=优先级最低,所以x/=3+6+2/3+6+2 所以x=0 来源: https://www.cnblogs.com/kxzh/p/8598048.html

STM32中的宏定义及库函数分析

随声附和 提交于 2020-03-07 00:31:41
. 使用KEIL5开发STM32可以使用"GPIOB->ODR"这种方式来给GPIOB的寄存器ODR赋值,因为在STM32中同属于一个外设的所有 寄存器地址基本是相 邻的(有些会有保留寄存器),因此我们可以借助C语言里面的 结构体成员地址递增 的特点来将某个外设的所有寄存器写入到一个结构体里面,然后定义一个结构体指针指向这个外设的寄存器基地址,这样我们就可以通过这个结构体指针来访问这个外设的所有寄存器。 STM32寄存器操作 ST官方为STM32系列处理器都编写了一个stm32f10x.h的文件,通过这个文件定义了STM32的所有外设寄存器。通过引用这个.h文件,我们可以在C文件中方便的找到对应的寄存器。 GPIOE -> CRL & - 0XFF OFFFFF; GPIOE -> CRL = 0X00300000 ; //PE5推挽输出 GPIOE -> ODR = 1 << 5 ; //PE5输出高 可以看出“GPIOE”是个宏定义,是一个指向地址 GPIOE_BASE 的结构体指针,结构体为 GPIO_TypeDef , GPIO_TypeDef 和 GPIOE_BASE 的定义如下 # define GPIOE ((GPIO TypeDef *) GPIOE BASE) typedef struct { __IO uint32_t CRL ; __IO uint32_t

宏的使用

僤鯓⒐⒋嵵緔 提交于 2020-03-06 16:42:36
写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性等等。下面列举一些成熟软件中常用得宏定义。。。。。。 1,防止一个头文件被重复包含 #ifndef COMDEF_H #define COMDEF_H //头文件内容 #endif 2,重新定义一些类型,防止由于各种平台和编译器的不同,而产生的类型字节数差异,方便移植。 typedef unsigned char boolean; /* Boolean value type. */ typedef unsigned long int uint32; /* Unsigned 32 bit value */ typedef unsigned short uint16; /* Unsigned 16 bit value */ typedef unsigned char uint8; /* Unsigned 8 bit value */ typedef signed long int int32; /* Signed 32 bit value */ typedef signed short int16; /* Signed 16 bit value */ typedef signed char int8; /* Signed 8 bit value */ //下面的不建议使用 typedef

关于C/C++中宏定义的一些新认识

喜你入骨 提交于 2020-03-02 08:23:04
在项目开发的过程中会遇到很多的宏定义,宏定义的作用目前本人知道的有三种有法: 第一种: #define OK 1 这种用法可以直接了当的表明代码的用意,从而防止“魔数”的出现,恰当的宏定义一些常量值可以有效的增加代码的可读性。 第二种: #define MAX(a, b) ( (a) > (b) ? (a) : (b) ) 这种宏定义函数的方法可以使代码变得更简洁,而且可以提高代码的执行效率,我们知道程序在调用宏定义时,是在代码执行时宏定义的地方直接进行替换,所以不会像调用函数那样进行压栈,让PC指针跳转另一块内存区域,从而使执行效率提高。在编译器的头文件中也有很多类似于这种方式的宏定义,只不过函数的实体是单独提取出来的。 第三种:#define function(...) 第一次遇到这种定义的时候感觉特别奇怪,因为它没有实体,宏替换时没有具体的操作内容,可这又有什么用呢?答案是这种宏定义的作用是一种“占位”,即宏定义了一个函数,这个函数里面的参数有多少个无所谓,它告诉了编译器已经存在这个函数了,你不可以重新再定义一个和它重名的函数,否则会报错,这种定义在大型的项目中很常见,从而防止不同的程序员在作业中定义同一种函数。 来源: oschina 链接: https://my.oschina.net/u/1032782/blog/786778

typedef 类型重命名 和 #define 宏定义(1)

大憨熊 提交于 2020-03-02 05:57:45
http://www.blogjava.net/jasmine214--love/archive/2010/11/29/339307.html 在现实生活中,信息的概念可能是长度,数量和面积等。在C语言中,信息被抽象为int、float和double等基本数据类型。 从基本数据类型名称上, 不能够看出其所代表的物理属性 ,并且int、float和double为系统关键字,不可以修改。 为了解决用户自定义数据类型名称的需求,C语言中引入类 型重定义语句typedef ,可以为数据类型定义新的类型名称,从而 丰富数据类型所包含的属性信息 。 typedef的语法描述 : typedef 类型名称 类型标识符; 例如:typedef double LENGTH; typedef unsigned int COUNT; typedef 的主要应用有如下的几种形式 : 1) 为基本数据类型定义新的类型名 。例如: typedef unsigned int COUNT; typedef double AREA; 此种应用的主要目的,首先是丰富数据类型中包含的属 性信息,其次是为了系统移植的需要,稍后详细描述。 2) 为自定义数据类型(结构体、公用体和枚举类型)定义简洁的类型名称(在c++中没有这个必要了,因为直接可以使用类型名定义变量,前面不用加struct) 。例如: struct

预处理指令--宏定义

元气小坏坏 提交于 2020-03-02 05:44:11
预处理指令简介 •C语言在对源程序进行编译之前,会先对一些特殊的预处理指令作解释(比如之前使用的#include文件包含指令),产生一个新的源程序(这个过程称为编译预处理),之后再进行通常的编译 •为了区分预处理指令和一般的C语句,所有预处理指令都以符号“#”开头,并且结尾不用分号 •预处理指令可以出现在程序的任何位置,它的作用范围是从它出现的位置到文件尾。习惯上我们尽可能将预处理指令写在源程序开头,这种情况下,它的作用范围就是整个源程序文件 •C语言提供的预处理指令主要有:宏定义、文件包含、条件编译 宏定义分类 •宏定义可以分为2种: –不带参数的宏定义 –带参数的宏定义 一、不带参数的宏定义 •1.一般形式 •#define 宏名 字符串 •比如 #define ABC 10 •右边的字符串也可以省略,比如#define ABC 2.作用 •它的作用是在编译预处理时,将源程序中所有"宏名"替换成右边的"字符串",常用来定义常量。 •接下来写个程序根据圆的半径计算周长 宏定义 #include <stdio.h> // 源程序中所有的宏名PI在编译预处理的时候都会被3.14所代替 #define PI 3.14 // 根据圆的半径计radius算周长 float girth(float radius) { return 2 * PI *radius; } int main ()