1. 宏中的#

宏中的#的功能是将其后面的宏参数进行字符串化操作(Stringizing operator),简单说就是在它引用的宏变量的左右各加上一个双引号。

如定义好#define STRING(x) #x之后,下面二条语句就等价。

char *pChar = "hello";  ==  char *pChar = STRING(hello);

还有一个#@是加单引号(Charizing Operator)

#define makechar(x)  #@x; ==  char ch = makechar(b);与char ch = 'b';等价。

注意,宏中遇到#或##时就不会再展开宏中嵌套的宏了。

比如使用char *pChar =STRING(__FILE__);虽然__FILE__本身也是一个宏,但编译器不会展开它,所以pChar将指向"__FILE__"。

因此要加一个中间转换宏,先将__FILE__解析成你希望的字符串。

#define _STRING(x) #x

#define STRING(x) _STRING(x)

再调用下面语句将输出带""的源文件路径

char* pChar = STRING(__FILE__);

printf("%s %s\n", pChar, __FILE__);

2.  宏中的##

##的功能:拼接符号(Token-pasting operator)。

eg. #define paster( n ) printf( "token"#n" = %d\n", token##n )

int token9 = 100;

再调用  paster(9);宏展开后token##n直接合并变成了token9。整个语句变成了 printf( "token""9"" = %d", token9 );

在C语言中字符串中的二个相连的双引号会被自动忽略,于是上句等同于 printf("token9 = %d", token9);。

即输出token9 = 100.

3. extern "C"

extern "C"的真实目的是实现类C和C++的混合编程。在C++源文件中的语句前面加上extern "C",表明它按照类C的编译和连接规约来编译和连接,而不是C++的编译的连接规约,但仍然要遵守C++的类型检测、参数转换规则。这样在类C的代码中就可以调用C++的函数/变量等。(注:类C,代表的是跟C语言的编译和连接方式一致的所有语言)

4. C++中调用C的代码

假设一个C的头文件cHeader.h中包含一个函数print(int i),为了在C++中能够调用它,必须要加上extern关键字(原因在extern关键字那节已经介绍)。它的代码如下:

1
2
3
4
5
6
#ifndef C_HEADER
#define C_HEADER
 
extern void print(int i);
 
#endif C_HEADER

相对应的实现文件为cHeader.c的代码为:

1
2
3
4
5
6
#include <stdio.h>
#include "cHeader.h"
void print(int i)
{
    printf("cHeader %d\n",i);
}

现在C++的代码文件C++.cpp中引用C中的print(int i)函数:

1
2
3
4
5
6
7
8
9
extern "C"{
#include "cHeader.h"
}
 
int main(int argc,char** argv)
{
    print(3);
    return 0;
}

5. C中调用C++的代码

现在换成在C中调用C++的代码,这与在C++中调用C的代码有所不同。如下在cppHeader.h头文件中定义了下面的代码:

1
2
3
4
5
6
#ifndef CPP_HEADER
#define CPP_HEADER
 
extern "C" void print(int i);
 
#endif CPP_HEADER

相应的实现文件cppHeader.cpp文件中代码如下:

1
2
3
4
5
6
7
8
#include "cppHeader.h"
 
#include <iostream>
using namespace std;
void print(int i)
{
    cout<<"cppHeader "<<i<<endl;
}

在C的代码文件c.c中调用print函数:

1
2
3
4
5
6
extern void print(int i);
int main(int argc,char** argv)
{
    print(3);
    return 0;
}

注意在C的代码文件中直接#include "cppHeader.h"头文件,编译出错。而且如果不加extern int print(int i)编译也会出错

C/C++语言补缺 宏- extern "C"-C/C++互调的更多相关文章

  1. c 语言中宏定义和定义全局变量的区别

    宏定义和定义全局变量的区别: 1 作用时间不同. 宏定义在编译期间即会使用并替换,而全局变量要到运行时才可以. 2 本质类型不同. 宏定义的只是一段字符,在编译的时候被替换到引用的位置.在运行中是没有 ...

  2. C语言中宏定义(#define)时do{}while(0)的价值(转)

    C语言中宏定义(#define)时do{}while(0)的价值 最近在新公司的代码中发现到处用到do{...}while(0),google了一下,发现Stack Overflow上早有很多讨论,总 ...

  3. 注解是建立在class文件基础上的东西,同C语言的宏有异曲同工的效果

    注解是建立在class文件基础上的东西,同C语言的宏有异曲同工的效果 https://www.cnblogs.com/deman/p/5519901.html @是java注解,即annotation ...

  4. C语言的宏macro的使用

    C's Macro Introduction 1.The Connect Macros: ## 这是一个预处理连接符,这个操作符主要用来将两个符号连接成为一个完整的宏符号.通过下面的代码,可以看到其具 ...

  5. C语言基础--宏

    宏在C语言中经常使用,在linux的源码中可以看到很多宏的高级应用.因此不理解宏,就很难理解代码.本文参考一些互联网资料做一些总结,希望给大家带来帮助. 先说说使用宏的优点及缺点: 优点: 1.提高代 ...

  6. C语言高级宏技巧

    特殊符号#.## (1)# When you put a # before an argument in a preprocessor  macro, the preprocessor turns t ...

  7. C语言之宏

    所谓的宏就是一种预处理命令,什么是与处理呢?即在编译过程之前先对程序代码做出的必要的转换处理.宏有两个作用: 1.当遇到需要将程序某个特定的数量在程序中出现的所有实例通通加以修改时,程序只需改动一处即 ...

  8. 【编程基础】C语言常见宏定义

    我们在使用C语言编写程序的时候,常常会使用到宏定义以及宏编译指令,有的可能比较常用,有的可能并不是很常用,是不是所有的C语言宏定义以及宏指令你都清楚呢? 指令 用途详细介绍 # 空指令,无任何效果 # ...

  9. C语言在宏定义中使用语句表达式和预处理器运算符

    语句表达式的亮点在于定义复杂功能的宏.使用语句表达式来定义宏,不仅可以实现复杂的功能,而且还能避免宏定义带来的歧义和漏洞.下面以一个简单的最小值的宏为例子一步步说明. 1.灰常简单的么,使用条件运算符 ...

随机推荐

  1. [Xcode 实际操作]四、常用控件-(8)UITextField控件的使用

    目录:[Swift]Xcode实际操作 本文将演示文本输入框控件的基本用法. 文本输入框主要用来接收和显示用户输入的内容. 在项目导航区,打开视图控制器的代码文件[ViewController.swi ...

  2. 误删重要文件怎么办?学会Linux 救援模式再也不担心

    背景 在运用Linux时会出现一些误操作,导致系统无法正常使用,比如删除了某个重要依赖库,或者删除了rpm等等.在这里记录下具体的操作步骤,供以后参考. 意义 学会在使用Linux系统出现误删除系统重 ...

  3. Java中keytool管理证书

    1.创建证书库以及第一个证书 keytool -genkeypair -alias "wangpass" -keyalg "RSA" -keystore &qu ...

  4. Codeforces 1161B(判断旋转对称)

    要点 外层暴力枚举转的"角度",会发现肯定是n的约数 对于m条线段想判定当前的"角度"是否ok,每个线段只要管它自己的下一个即可,不必画个圈遍历一遍 之后将本来 ...

  5. 如何直接修改cf,of等标志位的值?

    如何直接修改 cf,of 等 标志寄存器位的值? 我记得在哪个教程里见过,但是不太记得了… 貌似是在yjx驱动教程里面… 我想弄这个的原因是想验证 网上查到的 各种跳转语句(ja,jl,jg等) 需要 ...

  6. python3+Appium自动化02-Capability配置

    基本参数 参数 描述 实例 automationName 自动化测试引擎 Appium或 Selendroid platformName 手机操作系统 iOS, Android, 或 FirefoxO ...

  7. CentOS mini 和 nginx 的安装和配置要点

    1.安装VMware Player    版本:5.0.2 build-1031769 2.安装XShell    版本:Build 0126 3.安装CentOS    版本:6.4-x86_64- ...

  8. Murano Weekly Meeting 2015.07.21

    会议时间: 2015.07.21 主持人: Kirill Zaitsev, core from Mirantis 会议摘要:  1.murano client和murano dashboard升级到y ...

  9. C# 用正则表达式判断字符串是否为纯数字

    Regex regex = new System.Text.RegularExpressions.Regex("^(-?[0-9]*[.]*[0-9]{0,3})$"); stri ...

  10. java 中的阻塞队列

    1.什么是阻塞队列: 支持阻塞的插入方法,意思是当队列满时,队列会阻塞插入元素的线程,知道队列不满. 支持阻塞的移除方法:意思是在队列为空时,获取元素的线程会等待队列变为非空. 插入和移除操作的4种处 ...