zoukankan      html  css  js  c++  java
  • externn "C"解析

    1.揭密extern "C"

    extern "C"包含双重含义,从字面上即可得到:首先,被它修饰的目标是 "extern”的;其次,被它修饰的目标是 "C”的。
    首先来看一下 "extern”的含义
    a.在一个文件内,如果外部变量不在文件的开头定义,其有效范围只限定在定义到文件的结束处。如果在定义前需要引用该变量,则要在引用之前用关键字 "extern” 对该变量做“外部变量声明”,表示该变量是一个已经定义的外部变量。有个这个声明,就可以从声明处起合理地使用该变量了。"extern”起到了扩展作用域的作用。

    复制代码
    //.c
    #include <stdio.h>
    void main()
    {
        extern A;//用extern声明外部变量;若变量为int类型,类型名可写也可以省略。
        printf("%d", A);
    }
    int A=100;
    复制代码

    b.在多文件的程序中,如果多个文件都要使用同一个外部变量,不能在各个文件中各定义一个外部变量,否则会出现“重复定义”的错误。正确的做法是:在任一个文件中定义外部变量,其他文件用 "extern”对变量做“外部变量声明”。在编译和连接时,系统会由此知道该变量是一个已经在别处定义的外部变量,并把另一文件中外部变量的作用域扩展到本文件,这样在本文件就可以合法地使用该外部变量了。

    复制代码
    //file1.c
    #include <stdio.h>
    int A = 100;//定义外部变量
    void main()
    {
        printf("%d",power());
    }
    
    //file2.c
    extern A;//声明A为一个已定义的外部变量
    int power()
    {
        return A*A;
    }
    复制代码

    extern只用作声明,而不用于定义。extern说明变量或者函数定义在其他的源文件里,而不用include头文件的方式来引用该函数,在链接时,链接器在各个模块中搜索这个变量或者函数来进行最终链接。
    c.外部函数
    在定义函数时,如果在最左端加关键字extern,表示此函数是外部函数。C语言规定,如果在定义时省略extern,则隐含为外部函数。而内部函数必须前加static关键字;
    在需要调用此函数的文件中,用extern对函数作声明,表示该函数是在其他文件中定义的外部函数。
    "C”的含义:(extern “C”)
    C++通过函数参数的不同类型支持重载机制,编译器根据参数为每个重载函数产生不同的内部标识符。例如编译器为void Eat(Beef …);void Eat(Fish …);void Eat(Chicken …);三个Eat 函数产生象_eat_beef、_eat_fish、_eat_chicken 之类的内部标识符(不同的编译器可能产生不同风格的内部标识符)。
    如果 C++程序要调用已经被编译后的C 函数,该怎么办?
    假设某个 C 函数的声明如下:

    void foo(int x, int y);

    该函数被C 编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字用来支持函数重载和类型安全连接。由于编译后的名字不同,C++程序不能直接调用C 函数。C++提供了一个C连接交换指定符号extern“C”来解决这个问题。
    例如:

    复制代码
    extern “C”
    {
    void foo(int x, int y);
    … // 其它函数
    }
    或者写成
    extern “C”
    {
    #include “myheader.h”
    … // 其它C 头文件
    }
    复制代码

    这就告诉C++编译译器,函数foo 是个C 连接,应该到库中找名字_foo 而不是找_foo_int_int。C++编译器开发商已经对C 标准库的头文件作了extern“C”处理,所以我们可以用#include 直接引用这些头文件。

    2.extern "C"程序实例

    假设有C文件:

    复制代码
    //c.h
    #ifndef _C_H_
    #define _C_H_
    
    extern int add(int x, int y);
    
    #endif
    复制代码
    //c.c
    int add(int x, int y)
    {
        return x+y;
    }

    在C++下调用add()函数

    复制代码
    //cplusplus.cpp
    #include <iostream>
    #include "c.h"
    using namespace std;
    void main()
    {
        add(1, 0);
        system("Pause");
    }
    复制代码

    产生错误:无法解析的外部符号 "int __cdecl add(int,int)" (?add@@YAHHH@Z),该符号在函数 _main 中被引用
    为了解决这个问题,我们需要使用extern "C"。改写C文件

    复制代码
    //c.h
    #ifndef _C_H_
    #define _C_H_
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    extern int add(int x, int y);
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif
    复制代码

    文件为*.c,__cplusplus没有被定义,extern "C" {}这时没有生效,对于C语言只是extern int add(int, int);而编译c++源文件,__cplusplus被定义,对于C++他看到的是extern "C" {extern int add(int, int);},编译器就会知道add(1, 0)调用的是C连接。
    最后:很多DLL的生成文件(XXX.c)中常出现extern "C" ,windows采用C语言编译创建dll,C程序可以正确调用DLL,而当用户使用C++调用DLL时,extern "C" {}就起作用了。

    转自:extern "C"的简单解析 - 侯凯 - 博客园
    http://www.cnblogs.com/houkai/archive/2013/06/05/3118807.html

  • 相关阅读:
    java处理数据库date类型数据
    in与exist , not in与not exist 的区别
    Eclipse的调试功能的10个小窍门
    关于Synchornized,Lock,AtomicBoolean和volatile的区别介绍
    推荐使用concurrent包中的Atomic类
    深入 Java 调试体系: 第 1 部分,JPDA 体系概览
    dom 绘制正方形
    dom 拖拽div
    dom 按着shift多选
    dom select选单
  • 原文地址:https://www.cnblogs.com/johnleo/p/extern_c.html
Copyright © 2011-2022 走看看