C语言中定义变量“#X”,”X##”, “##X” 和“##X##”解析

关于#和##

在C语言的宏中,#的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。比如下面代码中的宏:

1. #使用

#define WARN_IF(EXP) /

do{ if (EXP) /

fprintf(stderr, "Warning: " #EXP "/n"); } /

while(0)

那么实际使用中会出现下面所示的替换过程:

WARN_IF (divider );  其中divider == 0

被替换为

do {

  if (divider == 0)

  fprintf(stderr, "Warning" "divider == 0" "/n");

} while(0);

这样每次divider(除数)为0的时候便会在标准错误流上输出一个提示信息。

2. ##使用

而## 被称为连接符(concatenator),用来将两个Token连接为一个Token。注意这里连接的对象是Token就行,而不一定是宏的变量。比如你要做一个菜单项命令名和函数指针组成的结构体的数组,并且希望在函数名和菜单项命令名之间有直观的、名字上的关系。那么下面的代码就非常实用:

struct command

{

  char * name;

  void (*function) (void);

};

#define COMMAND(NAME) { NAME, NAME ## _command }  此处的##表示后面有内容与NAME链接

// 然后你就用一些预先定义好的命令来方便的初始化一个command结构的数组了:

struct command commands[] = {

  COMMAND(quit),

  COMMAND(help),

  ...

}

COMMAND宏在这里充当一个代码生成器的作用,这样可以在一定程度上减少代码密度,间接地也可以减少不留心所造成的错误。我们还可以n个##符号连接 n+1个Token,这个特性也是#符号所不具备的。比如:

#define LINK_MULTIPLE(a,b,c,d) a##_##b##_##c##_##d //注意这里的规则(a##开头,##d结束,中间都用##x##)

typedef struct _record_type LINK_MULTIPLE(name,company,position,salary);

// 这里这个语句将展开为:

// typedef struct _record_type name_company_position_salary;

个人认为##类似 运算符+ 起到连接的作用。

3 再看一个#使用如下:

#define display(name) printf(""#name"")
int main() {
  display(name);
}

运行结果是name,为什么不是"#name"呢? 
---------------------------------------------------------------

#在这里是字符串化的意思 
printf(""#name"") 相当于 
printf("" "name" "")

原文地址:https://www.cnblogs.com/asasooo998/p/9483415.html

时间: 2024-11-08 21:31:44

C语言中定义变量“#X”,”X##”, “##X” 和“##X##”解析的相关文章

C语言中定义全局变量

(1)在C语言的头文件中定义变量出现的问题 最好不要傻嘻嘻的在头文件里定义什么东西.比如全局变量: /*xx头文件*/ #ifndef  _XX_头文件.H #define  _XX_头文件.H int A; #endif 那么,很糟糕的是,这里的int A是个全局变量的定义,所以如果这个头文件被多次引用的话,你的A会被重复定义,显然语法上错了.只不过有了这个#ifndef的条件编译,所以能保证你的头文件只被引用一次,不过也许还是不会出岔子,但若多个c文件包含这个头文件时还是会出错的,因为宏名有

case中定义变量

1.c语言switch/case中定义变量 case 0: int b = 0 ; printf("0");break; case 1: printf("1");break; default: printf("default");break; C和C++都会报错 情况1: case 0: int b; b = 0 ; printf("0");break; case 1: printf("1");break;

Go语言中的变量

1 概述 变量(Variable)是程序运行过程中,内容可以变化(修改)的量,变量的功能是存储用户的数据,是计算机语言中能储存计算结果或能表示值抽象概念.变量,是通过变量的标识符定位值的过程.变量的内存模拟演示: 2 定义:声明和初始化 定义变使用var关键字,需要指定其类型,可以同时初始化,如果没有指定初始化值,则使用类型的默认值,语法如下: // 声明变量,未初始化(默认值初始化) var name string // 声明变量,特定值初始化 var user string = "Hank&

C 语言中的变量为什么不能以数字打头

C 语言中的变量为什么不能以数字打头? C 语言中的变量为什么不能以数字打头? 不要告诉我编译原理书上有.我暂时看不懂. 除了下面的解释外, “假如变量名允许以数字开头的话,那么语法分析器在解析一个全部为数字的字串的时候,就无法判断它是一个数字常量还是一个变量名了” 还有别的解释吗? 假如变量是2n呢?也可以和数字2区别啊?为什么不行呢? C语言这样规定是不是单纯为了编译器词法分析简单啊?还有别的原因吗? 如果你知道就跟我好好说说吧. 没有规定就不成方圆,在最初的时候如果没有那么多的规定,这样基

freemarker 模板中定义变量

在模板中可以定义三种类型的变量: 简单变量:它能从模板中的任何位置来访问,或者从使用 include 指令引入的模板访问.可以使用 assign 或 macro 指令来创建或替换这些变量. 局部变量:它们只能被设置在宏定义体内,而且只在宏内可见.一个局部变量的生存周期只是宏的调用过程.可以使用 local 指令在宏定义体内创建或替换局部变量. 循环变量:循环变量是由指令(如 list )自动创建的,而且它们只在指令的开始和结束标记内有效.宏的参数是局部变量而不是循环变量. 示例:使用 assig

认识C#语言中的变量和数据类型

C#语言中的变量 概念:一块储存数据的内存空间,并且该内存区域的数据内容可以变化 变量的三要素:数据类型.变量名.变量值 先声明后赋值 变量的声明:指定一块内存空间,用于存放数据 语法:数据类型 变量名 例如:int number;  用于存放整数 变量的赋值: 例如:int number; number=6;  用于存放整数 变量命名 硬性要求: 1.变量只能有数字.字母.下划线组成 2.变量名不得以数字开头 3.名称不能与关键字相同 4.同一个函数中变量名不得相同 软性要求: 1.变量名能够

go语言中在变量后加上接口是什么意思?

如题刚刚开始学习go 语言有些不懂: a.Data = make(map[string]interface{}) 我认为它是在申请a.Data map为字符串类型的空间,那么它后面接一个空的interface是什么意思? go语言中在变量后加上接口是什么意思? >> golang 这个答案描述的挺清楚的:http://www.goodpm.net/postreply/golang/1010000008853468/go语言中在变量后加上接口是什么意思.html

c语言头文件中定义变量

最近在看一个PHP的扩展源码,编译的时候的遇到一个问题: ld: 1 duplicate symbol for architecture x86_64 仔细看了一下源码,发现在头文件中 出现了全局变量的定义 ZEND_DECLARE_MODULE_GLOBALS(xx) 简单开来,可以这么理解 // t1.h #ifndef T1_H #define T1_H int a = 0; #endif //------------------ //t1.c #include "t1.h" #

如何在switch case中定义变量(不用花括号)

这个周末有幸见到了几位神交已久的库友(天天/迪迪/丁丁),大家一起扯了些有的没的,很开森! 天天考了我一个问题,在C语言里面,如何在switch case中定义一个变量?要求是不用花括号. 这个问题是背景是,下面的代码是编译不过的,因为在case后面不能直接定义变量. switch (v) {    case 1:       int a;       get_value_of_xx(&a);       set_yy(a);       break;    case 2:       //do