`
yesjavame
  • 浏览: 678488 次
  • 性别: Icon_minigender_2
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

关于gcc扩展中的宏定义中用 "#" 和 "##"

GCC 
阅读更多

关于gcc扩展中的宏定义中用 "#" 和 "##"

今天测试了宏定义中的 "#" 和 "##" 的区别。

结果如下:

"#" 代表和一个字符串相连接

"##" 代表和一个符号连接,符号可以是变量,或另一个宏符号。

举例如下:

宏定义如下

(1)

#define DEV_FILE_NAME "/dev/test_kft"

#define OPEN_FILE(fd, n) \
{ \
fd = open(DEV_FILE_NAME #n,O_RDONLY); \
if(fd < 0) \
{ \
printf("Open device error\n"); \
return 0; \
} \
}

如此调用:

OPEN_FILE(fd1, 1);
OPEN_FILE(fd2, 2);
OPEN_FILE(fd3, 3);
OPEN_FILE(fd4, 4);
OPEN_FILE(fd5, 5);
OPEN_FILE(fd6, 6);

用gcc -E展开后,如下

2299: { fd1 = open("/dev/test_kft" "1",00); if(fd1 < 0) { printf("Open device error\n"); return 0; } };
2300: { fd2 = open("/dev/test_kft" "2",00); if(fd2 < 0) { printf("Open device error\n"); return 0; } };
2301: { fd3 = open("/dev/test_kft" "3",00); if(fd3 < 0) { printf("Open device error\n"); return 0; } };
2302: { fd4 = open("/dev/test_kft" "4",00); if(fd4 < 0) { printf("Open device error\n"); return 0; } };
2303: { fd5 = open("/dev/test_kft" "5",00); if(fd5 < 0) { printf("Open device error\n"); return 0; } };
2304: { fd6 = open("/dev/test_kft" "6",00); if(fd6 < 0) { printf("Open device error\n"); return 0; } };

如果没有定义DEV_FILE_NAME ,就是

2299: { fd1 = open(DEV_FILE_NAME "1",00); if(fd1 < 0) { printf("Open device error\n"); return 0; } };
2300: { fd2 = open(DEV_FILE_NAME "2",00); if(fd2 < 0) { printf("Open device error\n"); return 0; } };
2301: { fd3 = open(DEV_FILE_NAME "3",00); if(fd3 < 0) { printf("Open device error\n"); return 0; } };
2302: { fd4 = open(DEV_FILE_NAME "4",00); if(fd4 < 0) { printf("Open device error\n"); return 0; } };
2303: { fd5 = open(DEV_FILE_NAME "5",00); if(fd5 < 0) { printf("Open device error\n"); return 0; } };
2304: { fd6 = open(DEV_FILE_NAME "6",00); if(fd6 < 0) { printf("Open device error\n"); return 0; } };

所以可以很清楚的看出#n 解析出来的是"n" , 用于连接一个已有的字符串。

(2) 再来看 ## 是什么意思, 宏定义如下:

#define OPEN_FILE(fd, n) \
{ \
fd = open(DEV_FILE_NAME ##n,O_RDONLY); \
if(fd < 0) \
{ \
printf("Open device error\n"); \
return 0; \
} \
}

调用方式相同。

看宏展开:

2299: { fd1 = open(DEV_FILE_NAME1,00); if(fd1 < 0) { printf("Open device error\n"); return 0; } };
2300: { fd2 = open(DEV_FILE_NAME2,00); if(fd2 < 0) { printf("Open device error\n"); return 0; } };
2301: { fd3 = open(DEV_FILE_NAME3,00); if(fd3 < 0) { printf("Open device error\n"); return 0; } };
2302: { fd4 = open(DEV_FILE_NAME4,00); if(fd4 < 0) { printf("Open device error\n"); return 0; } };
2303: { fd5 = open(DEV_FILE_NAME5,00); if(fd5 < 0) { printf("Open device error\n"); return 0; } };
2304: { fd6 = open(DEV_FILE_NAME6,00); if(fd6 < 0) { printf("Open device error\n"); return 0; } };

现在看清楚了, ##n 的作用是把n直接连接在了一个符号的末尾. 好, 现在我们定义一个符号看看效果。

#define DEV_FILE_NAME1 "/dev/test_kft1"

再展开:


2299: { fd1 = open("/dev/test_kft1",00); if(fd1 < 0) { printf("Open device error\n"); return 0; } };
2300: { fd2 = open(DEV_FILE_NAME2,00); if(fd2 < 0) { printf("Open device error\n"); return 0; } };
2301: { fd3 = open(DEV_FILE_NAME3,00); if(fd3 < 0) { printf("Open device error\n"); return 0; } };
2302: { fd4 = open(DEV_FILE_NAME4,00); if(fd4 < 0) { printf("Open device error\n"); return 0; } };
2303: { fd5 = open(DEV_FILE_NAME5,00); if(fd5 < 0) { printf("Open device error\n"); return 0; } };
2304: { fd6 = open(DEV_FILE_NAME6,00); if(fd6 < 0) { printf("Open device error\n"); return 0; } };

很显然第一个符号被替换了, 因为是符号是宏的缘故。 这样我们也能把这一扩展特性应用在变量上。

分享到:
评论

相关推荐

    gcc扩展用法gcc扩展用法

    本文详细介绍了GCC的一些关键扩展特性,包括语句表达式、typeof关键字、零长度数组、可变参数宏和标号元素。通过这些特性的合理运用,不仅可以让代码变得更加灵活和高效,还能显著提高程序的可读性和可维护性。对于...

    GCC编译器内建宏定义

    本文将详细介绍Cygwin-GCC中的部分关键宏定义,这些宏定义能够反映编译器版本、数据类型、常量范围以及浮点数计算特性等方面的信息。 #### 编译器与平台信息 - **__STDC__**: 定义为`1`表示编译器遵循C语言标准...

    GCC核心扩展.doc

    在这个文档中,主要讨论的是GCC对C语言的一些核心扩展,特别是关于语句表达式、typeof关键字、零长度数组、可变参数宏以及标号元素初始化等特性。 1. **语句表达式(Statement Expressions)** GCC提供了一种扩展...

    Gcc扩展之typeof

    typeof 运算符的优点在于可以灵活地获取变量或表达式的数据类型,无需使用复杂的类型 casts 或宏定义。这使得代码更加简洁和易读。 typeof 运算符的应用 typeof 运算符的应用非常广泛,可以在各种编程场景中使用,...

    linux下GCC的使用简介

    - **作用**:处理包含文件、宏定义等预处理指令。 - **默认行为**:GCC 在编译过程中会自动调用 cpp 对源文件进行预处理。 - **命令示例**:`gcc -E -o gcctest.cpp gcctest.c` ##### 2. C 编译器 (gcc) - **功能*...

    巧用C语言宏定义实现自动注释调试代码

    宏定义在代码开发和调试过程中扮演着重要角色,尤其在大型项目中,能够有效地提升效率和代码可读性。本文将深入探讨如何巧用C语言的宏定义来实现自动注释调试代码,帮助开发者更好地理解和应用这一技巧。 首先,...

    MDK5 宏定义CC_ARM

    综上所述,通过宏定义的方式,CMSIS确保了代码能够在不同编译器环境下正确编译和运行,同时保留了各个编译器特有的优化特性。这对于跨平台开发是非常重要的,使得开发者能够在保持代码兼容性的同时,充分利用特定...

    gcc的中文版本手册

    描述部分概述了GCC的功能,包括预处理、编译、汇编和链接四个阶段,以及不同源文件扩展名对应的默认行为。例如,`.c`文件将被作为C语言源代码处理,`.cpp`或`.cc`文件将被视为C++源代码。 ##### OPTIONS GCC提供了...

    gcc C语言API

    这一API为开发者提供了丰富的接口来操作和扩展GCC编译器的功能。 #### 二、GCC C语言API的实现状态 ##### 2.1 C++1998/2003标准支持 在C++1998/2003标准方面,GCC实现了大部分的标准特性,并且对这些特性的支持...

    GCC.中文手册_it_gcc中文手册_gcc手册_

    预处理阶段处理宏定义、条件编译指令,并生成.i中间文件。编译阶段将预处理后的代码转换为汇编语言,生成.s文件。汇编阶段将汇编代码转换成机器码,形成.o目标文件。最后,链接器将所有目标文件以及必要的库文件合并...

    LINUX内核中的GCC特性

    本文旨在深入探讨Linux内核中所用到的GCC扩展,并解释如何在实际编码中应用这些扩展。 #### 二、GCC支持的C语言扩展特性 GCC支持的C语言扩展特性非常广泛,其中最重要的是类型发现、范围扩展等功能性扩展,以及一...

    Gcc核心源代码.pdf

    - **预处理**:通过预处理器对源代码进行预处理,处理宏定义、头文件包含等。 - **编译**:将预处理后的源代码编译成汇编代码或中间代码。 - **汇编**:将汇编代码转换为目标机器的机器码。 - **链接**:链接...

    Linux gcc.pdf

    预处理阶段,GCC 会将源代码转换为一个中间形式,去除注释和宏定义。编译阶段,GCC 会将中间形式转换为汇编代码。汇编阶段,GCC 会将汇编代码转换为机器代码。链接阶段,GCC 会将对象文件链接成一个可执行文件。 ...

    GCC中的预处理指令分析

    预处理阶段是GCC编译过程中的一个重要环节,它负责处理源代码中的宏定义、条件编译等特性。本文将深入分析GCC中的预处理指令及其内部实现机制。 #### 二、预处理指令概述 预处理指令是GCC在正式编译之前执行的一...

    GCC中文手册(吐血推荐)

    GCC(GNU Compiler Collection)作为GNU项目的重要组成部分,自问世以来便以其强大的功能和灵活性成为编程领域中不可或缺的工具之一。起初,GCC仅仅是一款C语言编译器,全称为GNU C Compiler。随着开源社区的不断...

    GCC中文手册pdf

    1. **预处理(Preprocessing)**:预处理器cpp会处理源代码中的宏定义、条件编译指令(#if, #ifdef, #endif)等,并将包含的头文件展开,生成一个新的中间文件.i。 2. **编译(Compilation)**:接下来,编译器cc1将...

Global site tag (gtag.js) - Google Analytics