什么是链接属性

链接属性与C语言中各个目标文件及函数的链接过程有关,用于认定不同文件的标识符(即程序中定义的各种名称,包括变量名、函数名)是否是同一个实体。更通俗地说,就是在两个不同文件中的变量、函数声明是否指向同一个实体。比如:a、b文件同时声明了变量c,链接属性就指定了这两处变量c是否是同一个c。

简单来说,链接属性的作用就是让你能在a文件中决定要不要访问b文件中的变量、函数。

链接属性的分类

链接属性有三种:

  • external - 外部链接
  • internal - 内部链接
  • none - 无链接

对于external属性的标识符,不同文件中出现的多个同名称标识符指向同一个实体。在C语言中,用extern关键字在声明中指定以引用其他文件中定义的相同标识符

对于internal属性的标识符,仅在当前文件内该标识符指向同一个实体。在C语言中,用static关键字在声明中指定让标识符变为该文件私有(只有对原本缺省的链接属性为external的标识符,才能用static关键字改变其链接属性为internal)。

对于none属性的标识符,在每个声明位置都是一个新的实体。C语言中,没有对应的关键字。

默认的链接属性

标识符的默认的链接属性与其出现的位置有关。

  • 程序的全局变量、所有函数默认的链接属性为external。

  • 其余标识符的默认链接属性为none。

在以下例子中,b、c、f的链接属性就是external:

typedef char *a;
int b;
int c(int d)
{
int e;
int f(int g);
}

实践应用

extern

在a文件中想要使用b文件中定义的external属性标识符,可使用extern关键字在a文件中声明。

即使该标识符所在位置默认链接属性为external,也建议使用extern关键字显式说明,有利于增加程序可读性。

static

在a文件定义了一个全局标识符,但不想被其他文件访问,可以对该标识符加上static关键字。

在a、b文件中定义了同样的标识符,通过static关键字可以避免多重定义问题。

再次提醒:只有对原本缺省的链接属性为external的标识符,才能用static关键字改变其链接属性为internal

一些细节

  1. 对于external属性的标识符,你可以在多个不同源文件中声明,但是你只能在一处初始化。否则就会出现重复定义的问题:multiple definition of 'a';
  2. extern关键字声明的标识符用于访问其他文件中定义的同名的标识符,因此无法进行初始化。如果你对extern声明的变量进行初始化就会生成警告:warning: ‘a’ initialized and declared ‘extern’
  3. 如果在其他文件中不存在相应的标识符定义,却在当前文件中使用了extern声明,会报错:undefined reference to 'a',原理同2。
  4. external属性的标识符总是静态存储类型。
  5. static关键字还有改变存储类型的作用,因此,其作用与上下文环境有关,只有对于默认链接属性为external的标识符,才有改变链接属性的作用。
  6. C++中,const变量隐含的具有internal属性,C中并不具有这一性质。

思考题

internal和none属性除了作用域不同还有什么区别?

以下代码一定程度上阐释了部分区别:

static int i; // definition
// static storage
// internal linkage void f(void)
{
extern int i; // declaration
// refers to the static i at file scope
// note that even though the specifier is extern
// its linkage is intern (this is legal in both C/C++)
{
int i; // definition
// automatic storage
// no linkage
}
}

实际上链接属性和作用域是两个概念。之所以产生以上问题,因为internal属性标识符出现的位置都是在文件作用域,而none往往在代码块作用域。此处想引起读者对内链接更深入的思考,见问题2。

文件作用域已经能让程序访问同一文件变量,那么再进行内部链接的意义在哪?

同一个标识符在链接中只能存在一个,那么通过内部链接的方式可以隔绝同名外部链接,且限定了外部编译单元不能访问该文件全局标识符。

a.c:

#include <stdio.h>

static int a=3;

int main(void)
{
extern int a;
printf("a=%d\n", a);
return 0;
}

b.c:

int a=1;

编译后结果为:

a=3

以上仅为不完善的个人猜想,抛开隔绝外部链接这一点不谈,就内部链接这一名称而言,笔者对为什么要在同一个文件内部使用链接的设计仍然存疑,但目前该话题的答案超出了笔者的理解,因此更深入的讨论暂时留白。

拓展:感兴趣的同学可以尝试学习链接相关知识,或许会找到更确定的答案。

参考

C语言链接属性的更多相关文章

  1. C语言链接属性总结

    1.什么是链接属性?   当组成一个程序的各个源文件分别被编译后,所有的目标文件以及那些从一个或多个函数库中引用的函数链接在一起,形成可执行程序. 标识符的链接属性决定如何处理在不同文件中出现的标识符 ...

  2. c语言3种链接属性: 外部(external), 内部(internal),无设置(none)

    c语言中,多个文件组合的时候,有可能标示名相同,那么这个时候编译器如何判别的呢?    c语言中有3种链接属性: 外部(external), 内部(internal),无设置(none)    外部( ...

  3. C语言中标识符的作用域、命名空间、链接属性、生命周期、存储类型

    Technorati 标签: C,标识符,作用域,命名空间,链接属性,生命周期,存储类型,scope,name space,linkage,storage durations,lifetime 无论学 ...

  4. C语言中的作用域、链接属性与存储属性

    C语言中的作用域.链接属性与存储属性 一.作用域(scope) 代码块作用域 表示{}之间的区域,下例所示,a可以在不同的代码块里面定义. #include<stdio.h> int ma ...

  5. C语言中变量和函数的作用域和链接属性

    C语言中变量和函数的作用域和链接属性 作用域 代码块作用域: 代码块指的是使用"{}"包围起来的部分. 在代码块中定义的变量,代码块之外是不能访问的. 代码块嵌套之后的变量作用域, ...

  6. C语言-存储类&作用域&生命周期&链接属性

    1.概念解析(1)存储类 a.存储类就是存储类型,也就是描述C语言变量在何种地方存储. b.内存有多种管理办法:栈.堆.数据段.bss段..text段......一个变量的存储类属性就是描述这个变量存 ...

  7. C语言中的作用域,链接属性和存储类型

    作用域 当变量在程序的某个部分被声明的时候,他只有在程序的一定渔区才能被访问,编译器可以确认4种不同类型的作用域:文件作用域,函数作用域,代码块作用域和原型作用域 1.代码块作用域:位于一对花括号之间 ...

  8. C语言作用域、链接属性和存储类型

    C/C++中作用域详解 作用域 编译器可以确认的4种作用域-代码块作用域.文件作用域.函数作用域和原型作用域,一般来说,标识符(包括变量名和函数名)声明的位置决定它的作用域. (1)代码块作用域 一对 ...

  9. 存储类&作用域&生命周期&链接属性

    链接属性 (1)大家知道程序从源代码到最终可执行程序,经历的过程:编译.链接. (2)编译阶段就是把源代码搞成.o目标文件,目标文件里面有很多符号和代码段.数据段.bss段等分段.符号就是编程中的变量 ...

随机推荐

  1. 使用java实现圆形运动

    1 package com.neuedu.test; 2 3 import java.awt.Graphics; 4 import java.awt.Image; 5 6 import com.neu ...

  2. go基础——数值传递与值传递

    package main import "fmt" /* 1.值类型:存储的是数值本身,数据传递给其他变量时传递的是数据的副本. int,float,string,bool,arr ...

  3. LeetCode随缘刷题之回文数

    package leetcode.day_01_30; /** * 给你一个整数 x ,如果 x 是一个回文整数,返回 true :否则,返回 false . * <p> * 回文数是指正 ...

  4. 利用LNMP实现wordpress站点搭建

    一.部署MySQL 1.1 二进制安装mysql5.6 # 准备用户,依赖包,二进制程序 [root@nginx ~]# yum install -y libaio perl-Data-Dumper ...

  5. tree目录结构

    https://www.cnblogs.com/richard-youth/p/6297827.html 常用命令 tree -Cd -L 3 相信很多使用过Linux的用户都用过tree命令,它可以 ...

  6. C# 字符串计算MD5

    public static string ComputeMD5 (string text) // 计算字符串的 MD5 { System.Security.Cryptography.MD5Crypto ...

  7. tip7:CentOS8虚拟机安装相关总结

    使用工具:Win10家庭版.WM12Pro.CentOS8. 一.安装 之前使用虚拟机安装操作系统使用的都是OpenSuse,也有相关备份.但是在Win10家庭版上用不了,启动电脑蓝屏(可能某些硬件不 ...

  8. (待补充)diff 算法解析

    今天,学习React的时候,底层提到了 diff算法,顺藤摸瓜, 也发现了VUE也使用了diff算法. mark一下,后续补充 infoq-VUE-diff算法 react-diff算法

  9. MYSQL文件复制及备份

    周末研究了下mysql的数据结构,记录下: 场景1:当从一台电脑的mysql的data中复制数据库的文件夹到另一台电脑上时会发现 表不存在,函数等也不存在 方法:1.需要将data根目录下的ibdat ...

  10. 只有PC端的报表工具使用太不方便了!有没有好用的手机报表app?

    马上到年底了,签订的销售合同需尽快回款,销售经理此时正在下午出差的出租车上,通过手中的手机他查看了一下今天的回款报表 项目已经进行到了关键期,项目经理正在奔赴项目城市的高铁列车上,项目今天的进度报表已 ...