string ToString() { return string.Format("{0},{1}", m_x, m_y); } } 上面是一个值类型的定义...,也许很多人象我一样,在平时工作中随意使用,也不会去管它有什么不同?...test(String s)内对s赋值为新字符串时,同样会生成一个新的对象,因此也不会影响到test方法体外的值。...,类似第1次输出中的解释一样,按值传递,方法体内修改的只是副本的值,也不会影响test体外的值....(因为P是值类型,p2与p1在内存中对应的是二个不同的地址,相互并不干扰), //然后临时生成的p2因为不再被使用,Main方法执行完成后,会自动清理
,通过在宏主体中编写不平衡的开放括号,可以创建一个从宏主体内部开始但在宏主体外部结束的宏调用。...,但是在宏主体中使用不平衡的开放括号只会造成混淆,应该避免。...运算符优先级问题 在大多数宏定义示例中,每次出现的宏参数名称都带有括号,并且另一对括号通常会包围整个宏定义,这是编写宏最好的方式。...x_ : y_; }) “({{…})”符号产生一个复合表达式,它的值是其最后一条语句的值。 如果不使用GNU C扩展,唯一的解决方案是在使用宏min时要小心。...例如计算foo(z)的值时,将其保存在变量中,然后在min中使用该变量: //假设foo返回int类型 #define min(X, Y) ((X) < (Y) ?
预处理器是在OC源文件编译过程中的一个部分,而且是第一个处理部分,预处理器的预也由此可见。...预处理器之宏 要知道,宏也是预处理器范畴内的内容,我们用的也很多: // 定义常量值 #define 宏名 值 //定义函数宏 #define 宏名(参数) 代码 // 移除宏 #undef 宏名 宏被定义后...定义函数宏的时候,有一个细节要注意,就是要多对参数使用括号: #defind SQUARE(x) ((x) * (x)) 为什么要这么麻烦?为什么不能直接 x * x?...,所以都应该使用括号。...此外,如果你的代码有多行,还应该使用大括号括起来: #define FUNC(a, b) {a = a + b; b = a - b;} 此外,不要过度使用宏!
这些参数可以在替换列表中根据需要出现任意次。 在宏的名字和左括号之间必须没有空格。如果有空格,预处理器会认为是在定义一个简单的宏,其中(x1,x2,…,xn)是替换列表的一部分。...##运算符 在C语言的宏中,"##"被称为 连接符(concatenator),它是一种预处理运算符, 用来把两个语言符号(Token)组合成单个语言符号。...宏定义中圆括号 在我们前面定义的宏的替换列表中有大量的圆括号。确实需要它们吗?答案是绝对需要。如果我们少用几个圆括号,宏可能有时会得到意料之外的——而且是不希望有的结果。...对于在一个宏定义中哪里要加圆括号有两条规则要遵守: 首先,如果宏的替换列表中有运算符,那么始终要将替换列表放在括号中: #define TWO_PI (2*3.14159) 其次,如果宏有参数,...becomes do { gets(str); puts(str); } while (0); */ 为什么在宏定义时需要使用do-while语句呢?
一、#define的基本语法 在C语言中,常量是使用频率很高的一个量。常量是指在程序运行过程中,其值不能被改变的量。常量常使用#define来定义。...Microsoft Word中对宏定义为:“宏就是能组织到一起作为一独立的命令使用的一系列word命令,它能使日常工作变得更容易”。...这个问题,的解决办法是在宏定义表达式两边加上一对括号就可以了。...#define DOUBLE( x) ( ( x ) + ( x ) ) 提示: 所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用...在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。 2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。 3.
使⽤命名空间的⽬的是对标识符的名称进⾏本地化,以避免命名冲突或名字污染 。 在同一个工程中,不同文件中定义的同名namespace会被认为是同一个namespace,不会冲突。...内联函数比较于宏 宏的回顾 #define ADD(a, b) ((a) + (b)) // 为什么不能加分号? // 为什么要加外⾯的括号? // 为什么要加⾥⾯的括号? 为什么不能加分号?...在调用宏的时候必须保证调用时写的与定义的宏函数格式一样,如果多加了分号的话那在调用的时候就会因为缺少分号而报错; 为什么要加外面的括号?...例如在使用宏函数进行运算cout << 3 * ADD( 1 , 2 ) << endl;时就会因为运算符优先级的问题而计算错误。所以在定义宏函数的时候将括号写准确有利于后续程序的稳定。...但加上括号后,宏展开为 ((a)++) + b,这在大多数编译器中是不允许的,因为不允许对括号内的表达式进行递增操作,从而避免了这种错误。
#define定义宏 (1)定义 #define 机制包括了⼀个规定,允许把参数替换到⽂本中,这种实现通常称为宏(macro)或定义宏 (define macro)。...替换⽂本时,参数x被替换成a + 1,所以这条语句实际上变成了: printf ("%d\n",a + 1 * a + 1 ); 所以实际上结果为:11 ✨✨解决办法: 在宏定义上加上两个括号...,这个问题便轻松的解决了~ #define SQUARE(x) (x) * (x) 所以⽤于对数值表达式进⾏求值的宏定义都应该⽤这种⽅式加上括号,避免在使⽤宏时由于参数中的操作符或邻近操作符之间不可预料的相互作...3.宏替换的规则 在程序中扩展#define定义符号和宏时,需要涉及⼏个步骤。 1. 在调⽤宏时,⾸先对参数进⾏检查,看看是否包含任何由#define定义的符号。...对于宏,参数名被他们的值所替换。 3. 最后,再次对结果⽂件进⾏扫描,看看它是否包含任何由#define定义的符号。如果是,就重复 上述处理过程。 注意: 1.
,包括全局变量,局部变量,函数声明或定义中的参数,带括号宏中的参数。...理由: 代码逻辑直观,易读; 在已有条件语句代码上增加新代码时不容易出错; 对于在条件语句中使用函数式宏时,没有大括号保护容易出错(如果宏定义时遗漏了大括号)。...ErrLog(__FILE__, __LINE__, fmt, ##__VA_ARGS__) 规则6.1 定义宏时,宏参数要使用完备的括号 宏参数在宏展开时只是文本替换,在编译时再求值。...当宏在调用点展开后,宏内定义的表达式和变量融合到调用代码中,可能会出现变量名冲突和宏内语句被分割等问题。...使用此类宏务必特别小心。 宏中包含不完整语句时,可以例外。比如用宏封装 for 循环的条件部分。 非多条语句,或单个 if/for/while/switch 语句,可以例外。
文件名在双引号内:先在当前目录中搜索文件,再到编译器的包含目录中搜索文件。 对于stdio.h文件来说,它是编译器自带的文件,在编译器的包含目录中。所以使用尖括号,即可找到该文件。...,参数n) 替换体 虽然由带参数的#define定义的宏函数,在使用方法上很像函数。但是,它的本质依然是将宏替换为对应的替换体。由此,如果简单地将其当做函数使用,会出现一些问题。...因此,为了保证宏函数展开后的表达式能够优先计算,请在替换体两边加上括号。 最后,为了保证不要在一个表达式中对同一个变量多次进行自增、自减操作。...} 在Visual Stduio 2019中,覆盖定义宏并不会导致编译报错而停止 不过,更妥当的做法是:使用预处理指令#undef,取消这个宏的定义,再重新定义它。...所以,我们将Person结构类型的定义与符号常量NAME_LENGTH,在文件person.h中也写了一遍。 为什么没有重定义报错 代码中出现了重复的声明或定义,构建时为什么不会出现重定义报错呢?
文件名在双引号内:先在当前目录中搜索文件,再到编译器的包含目录中搜索文件。 对于stdio.h文件来说,它是编译器自带的文件,在编译器的包含目录中。所以使用尖括号,即可找到该文件。...,参数n) 替换体 虽然由带参数的#define定义的宏函数,在使用方法上很像函数。但是,它的本质依然是将宏替换为对应的替换体。由此,如果简单地将其当做函数使用,会出现一些问题。...最后,为了保证不要在一个表达式中对同一个变量多次进行自增、自减操作。若宏函数的替换体内在一个表达式中多次使用同一个参数,那么请不要在宏函数的参数内填自增、自减表达式。...} 在Visual Stduio 2019中,覆盖定义宏并不会导致编译报错而停止 不过,更妥当的做法是:使用预处理指令#undef,取消这个宏的定义,再重新定义它。...所以,我们将Person结构类型的定义与符号常量NAME_LENGTH,在文件person.h中也写了一遍。 为什么没有重定义报错 代码中出现了重复的声明或定义,构建时为什么不会出现重定义报错呢?
#define 定义宏 #define 机制包含了一个规定,允许把参数替换到文本中,这种实现通常称为宏或者定义 宏的定义方式 #define name(parament-list) stuff parament-list...为参数 注: 1.参数列表的左括号必须与name紧邻,否则可能会被当成stuff 2.我们在定义宏用来求值的时候尽量都加上括号,避免在进行替换之后会因为优先级问题,导致结果不是我们预期想要的结果...所以宏比函数在程序的规模和速度方面更胜一筹。 宏与类型无关。 当然,宏相比函数也有缺点 每次使用宏的时候,一份宏定义的代码插入到程序中。除非宏比较短,否则可能会大幅度增加程序的长度。...3、宏参数的替换是不经过计算的,有可能会带有副作用,所以我们在写宏体的时候一般在能加括号的地方都不要吝啬括号,但有时候这也不能解决副作用的问题。函数在传参时传的是值,不会产生副作用。...6、函数在调用时会产生时间和空间上的开销;宏在调用时则没有,因为宏进行的只是简单的字符串替换。 7、如果使用宏比较多,宏体在展开时会产生大量的代码,大大降低运行时间。
这又这么解决: 在宏定义表达式的两边再加上一对括号就可以了。...#define DOUBLE( x ) ((x) + (x)) 所以我们得出结论: 用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用...2.4 #define 替换规则 在程序中扩展#define定义符号和宏时,需要涉及几个步骤。 在调用宏时,首先对其参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。...而对于函数来说,我们定义好的函数在程序中只留存一份,我们每次使用,只需要调用一下就行了。 宏是没法调试的。 宏由于类型无关,也就不够严谨。 这是它的一个优点,但同时也是缺点。...这个其实我们在讲宏的时候就演示过了,在使用宏的时候,有些地方如果我们不加括号,可能就会导致由替换产生的表达式因为操作符优先级的问题而并没有按照我们预想的次序进行求值。
其程序块结束行"}"的右方应加表明该程序块结束的标记"end of……", 尤其在多重嵌套时。 3.4 变量、常量、宏的注释 同一类型的标识符应集中定义,并在定义之前一行对其共性加以统一注释。...对单个标识符的注释加在定义语句的行尾。 全局变量一定要有详细的注释,包括其功能、取值范围、哪些函数或过程存取它以及存取时的注意事项等。 注释用"//…//"的格式。...5) 表达式中,若有多个操作符连写的情况,应使用空格对它们分隔: 6) 在两个以上的关键字、变量、常量进行对等操作时,它们之间的操作符前后均加一个空格;在两个以上的关键字、变量、常量进行非对等操作时,...在.c文件中: #define FILE_FLAG 在.h文件中:& 6.程序结构 6.1 基本要求 1) 有main()函数的.c文件应将main()放在最前面,并明确用void声明参数和返回值...2) 中断的开放和禁止 使用宏定义方式开放或禁止中断,宏定义语句放在EnDisInt.h头文件中。宏名的定义方法: 开放中断以Enable标识,宏名中包含中断名,宏名最后以Int结束。
宏定义在源程序中单独另起一行,换行符是宏定义的结束标志(不能在末尾加分号)。如果一个宏定义太长,一行不 够时,可采用续行的方法。续行是在键人回车符之前先键入符号"/"。...在新的宏定义中,可以使用前面已定义的宏名,示例: # define R 2.5 # define PI 3.1415926 # define Circle 2*PI*R # define Area PI...我这里为什么a和b要加括号?...所以在进行宏定义的时候,多加几个括号,总没问题。 ...宏进行定义时不会考虑参数的类型。 3. 参数宏的使用会使具有同一作用的代码块在目标文件中存在多个副本,即会增长目标文件的大小。 4.
#define 这个也不陌生吧,定义宏用的。 有关#define这个宏定义,在C语言中使用的很多,因为#define存在一些不足,C++强调使用const来定义常量。...并没有实现程序中的B+2的平方 * 预处理的时候,替换成如下的结果:b+2*b+2 * 正确的宏定义应该是:#define SQR(x) ((x)*(x)) * 所以,尽量使用小括号,将参数括起来...你无法对一个头文件中的一段代码作pragma once声明,而只能针对文件。 其好处是,你不必再费劲想个宏名了,当然也就不会出现宏名碰撞引发的奇怪问题。大型项目的编译速度也因此提高了一些。...#ifdef、#ifndef、#endif #ifdef用于判断某个宏是否定义,和#ifndef功能正好相反,二者仅支持判断单个宏是否已经定义 #endif用于终止#if预处理指令。...在判断某个宏是否被定义时,应当避免使用#if,因为该宏的值可能就是被定义为0。而应当使用#ifdef或#ifndef。 注意: #if、#elif之后的宏只能是对象宏。
其中DSP与FPGA通过两个带参宏进行数据交互(DSP与FPGA通过一块共享内存来实现数据交互,我这边的DSP只要往共享内存中写入数据即为往FPGA中写数据,往共享内存中读取数据就是读取FPGA发送过来的数据...volatile在嵌入式编程中用得很多,如在Cortex-M3内核MCU的内核文件的C函数内嵌汇编中使用了大量的volatile关键字: ?...此处等号右边的 (((volatile uint32*)base_addr)[(offset)])) 可以等价于: *(((volatile uint32*)base_addr) + offset)) 为什么要在宏函数实体的参数的两边加上括号呢...为什么要在宏函数实体的两边加上括号呢? 答:虽然有时候不加括号也没什么问题,但是,更严格的做法是给参数加括号、给宏函数实体加括号,这样可以避免二义性。...\n\n"); } // 验证宏函数FPGA_READ FPGA_READ(data_read, ptr, 5); // 此时data_read的值会被arr[5]的值覆盖 printf
) ); 这里还有一个宏定义: #define DOUBLE(x) (x) + (x) 定义中我们使用了括号,想避免之前的问题,但是这个宏可能会出现新的错误。...我们发现替换之后: printf ("%d\n",10 * (5) + (5)); 乘法运算先于宏定义的加法,所以出现了 55 这个问题,的解决办法是在宏定义表达式两边加上一对括号就可以了。...#define DOUBLE( x) ( ( x ) + ( x ) ) 提示: 所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用...在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。...最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。 注意: 宏参数和#define定义中可以出现其他#define定义的符号。
: #define DOUBLE(x) (x) + (x) 定义中我们使⽤了括号,想避免之前的问题,但是这个宏可能会出现新的错误。...我们发现替换之后: printf ("%d\n",10 * (5) + (5)); 乘法运算先于宏定义的加法,所以出现了 55 . 这个问题,的解决办法是在宏定义表达式两边加上⼀对括号就可以了。...#define DOUBLE( x) ( ( x ) + ( x ) ) 提示: 所以⽤于对数值表达式进⾏求值的宏定义都应该⽤这种⽅式加上括号,避免在使⽤宏时由于参数中的操作符或邻近操作符之间不可预料的相互作...在调⽤宏时,⾸先对参数进⾏检查,看看是否包含任何由#define定义的符号。如果是,它们⾸先被替换。 2. 替换⽂本随后被插⼊到程序中原来⽂本的位置。对于宏,参数名被他们的值所替换。 3....最后,再次对结果⽂件进⾏扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。 注意: 1. 宏参数和#define定义中可以出现其他#define定义的符号。
带参宏在我们的嵌入式编程中使用得非常多,其定义如下: define 标识符(参数列表) 字符序列 其中参数列表中的参数之间用逗号分隔,字符序列中应包含参数表中的参数。...在定义带参数的宏时,宏名标识符与左圆括号之间不允许有空白符,应紧接在一起,否则变成了无参数的宏定义。 并且,字符序列与其每一个参数必须用括号扩起来,否则该宏定义可能会产生二义性 。...带参宏与函数的区别 查看以上带参宏,我们发现带参宏似乎与函数似乎长得很像,它们之间有什么区别和联系呢?TI为什么要使用宏来对一些算法进行封装呢,难道使用函数来封装不可以吗?答案是可以的: ?...除此之外,宏与函数的不同点还有:宏是在预处理阶段展开,占用的是编译时间,函数实在程序运行时调用的,占用的是程序运行的时间;宏参数没有类型说明,也没有返回值的概念。...和使用函数相比,使用宏的不利之处在于每次使用宏时,一份宏定义代码的拷贝都会插入到程序中。除非宏非常短,否则使用宏会大幅度增加程序的长度。 还有一些任务根本无法用函数实现,但是用宏定义却很好实现。
领取专属 10元无门槛券
手把手带您无忧上云