浅谈C语言中的强符号、弱符号、强引用和弱引用

强符号、弱符号、强引用和弱引用

符号的概念

C语言中,符号通常指的是变量、函数或者地址的名称。当我们使用这些名字的时候,编译器会将其转换成对应的地址或者值。但是,有些情况下我们并不希望这些名字被编译器处理,而是需要自己处理这些名字所代表的地址或者值,这就需要了解符号的相关概念。

符号的属性

在C语言中,符号有四个属性:强符号、弱符号、强引用和弱引用。这四个属性是程序运行过程中的重要概念,深入理解它们有助于我们更好地理解链接和符号的工作原理。

强符号

强符号是指在链接过程中会被优先选中的符号。当程序中存在多个同名符号时,链接器会选择这些符号中属性最强的一个作为最终的符号。在C语言中,全局变量和函数都是强符号,它们的地址无法被改变,链接器会优先使用它们。

例如,我们声明了一个全局变量和一个函数:

int global_var = 0;

void func() {
    global_var = 1;
}

编译后得到的汇编代码如下:

_global_var:
    .long 0

_func:
    push ebp
    mov ebp, esp
    mov dword ptr [_global_var], 1
    pop ebp
    ret

可以看到,变量global_var和函数func都被编译器赋予了标号,这些标号成为了强符号。

弱符号

弱符号是指在链接过程中,如果存在多个同名符号,则链接器会选择属性最弱的符号作为最终的符号。在C语言中,静态变量和函数都是弱符号,它们的地址可以被改变。

例如,我们声明了一个静态变量和一个静态函数:

static int static_var = 0;

static void static_func() {
    static_var = 1;
}

编译后得到的汇编代码如下:

_static_var:
    .long 0

_static_func:
    push ebp
    mov ebp, esp
    mov dword ptr [_static_var], 1
    pop ebp
    ret

可以看到,静态变量static_var和静态函数static_func都被编译器赋予了标号,这些标号成为了弱符号。

强引用

强引用是指在程序中直接引用一个符号,链接器会将这个符号和它在程序中的位置联系起来。在C语言中,对全局变量和函数的直接引用都是强引用。

例如,我们在代码中使用了全局变量和函数:

#include <stdio.h>

int global_var;

void func();

int main() {
    global_var = 1;
    func();
    printf("global_var: %d\n", global_var);
    return 0;
}

编译后得到的汇编代码如下:

_main:
    push ebp
    mov ebp, esp
    mov dword ptr [_global_var], 1
    call _func
    push dword ptr [_global_var]
    push OFFSET FLAT:.LC0
    call _printf
    add esp, 8
    xor eax, eax
    pop ebp
    ret

可以看到,在代码中对全局变量global_var和函数func的引用都是强引用。

弱引用

弱引用是指在程序中间接引用一个符号,链接器不会将这个符号联系起来。在C语言中,对静态变量和函数的间接引用、对全局变量和函数的非直接引用都是弱引用。

例如,我们声明了一个静态变量和一个静态函数,通过另一个函数间接引用它们:

#include <stdio.h>

static int static_var = 0;

static void static_func() {
    static_var = 1;
}

void call_static_func() {
    static_func();
}

int main() {
    call_static_func();
    printf("static_var: %d\n", static_var);
    return 0;
}

编译后得到的汇编代码如下:

_static_var:
    .long 0

_static_func:
    push ebp
    mov ebp, esp
    mov dword ptr [_static_var], 1
    pop ebp
    ret

_call_static_func:
    push ebp
    mov ebp, esp
    call _static_func
    pop ebp
    ret

_main:
    push ebp
    mov ebp, esp
    call _call_static_func
    push dword ptr [_static_var]
    push OFFSET FLAT:.LC0
    call _printf
    add esp, 8
    xor eax, eax
    pop ebp
    ret

可以看到,在主函数中对静态变量static_var和静态函数static_func的引用都是弱引用,而在call_static_func函数中对静态函数static_func的引用是强引用。

总结

符号的属性对C语言程序链接和运行有着重要的影响。强符号和弱符号主要涉及到程序在链接阶段对同名符号的选择,并且强符号的地址无法被改变,而弱符号的地址是可以被改变的。强引用和弱引用主要涉及到程序中对符号的直接引用和间接引用。深入理解这些概念有助于我们更好地理解链接和符号的工作原理。

示例1

我们假设有两个文件a.cb.c,其中a.c定义了一个全局变量,b.c中包含了一个函数,这个函数对全局变量进行了修改。我们来看一下这个程序的运行结果,及其背后的原因。

a.c

#include <stdio.h>

int global_var = 0;

int main() {
    printf("before modify: %d\n", global_var);
    modify_global_var();
    printf("after modify: %d\n", global_var);
    return 0;
}

b.c

#include <stdio.h>

extern int global_var;

void modify_global_var() {
    global_var = 1;
}
$ gcc a.c b.c
$ ./a.out
before modify: 0
after modify: 1

可以发现,程序运行后,全局变量global_var的值从0变为了1。这是因为在链接阶段,链接器优先选择了a.c中定义的全局变量,并将这个全局变量与b.c中的函数进行了连接。因此,在b.c中修改全局变量的值,实际上是修改了a.c中定义的全局变量。

示例2

我们再来研究一个例子,这个例子中声明了一个静态变量和一个静态函数,这个函数对这个静态变量进行了修改。我们来看一下这个程序的运行结果,以及背后的原因。

#include <stdio.h>

static int static_var = 0;

static void static_func() {
    static_var = 1;
}

void call_static_func() {
    static_func();
}

int main() {
    call_static_func();
    printf("static_var: %d\n", static_var);
    return 0;
}
$ gcc main.c
$ ./a.out
static_var: 0

可以发现,程序运行结束后,静态变量static_var的值还是0,没有被函数修改。这是因为对静态变量和静态函数的引用都是弱引用,静态变量的地址可以被改变,而静态函数的优先级比全局变量低,因此链接器不会将静态函数与静态变量进行连接。因此,函数对静态变量的修改并没有生效。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅谈C语言中的强符号、弱符号、强引用和弱引用 - Python技术站

(0)
上一篇 2023年5月24日
下一篇 2023年5月24日

相关文章

  • postgresql限制某个用户仅连接某一个数据库的操作

    限制某个用户仅连接某一个数据库的操作可以通过在PostgreSQL中修改pg_hba.conf和postgresql.conf文件来实现。下面是具体步骤: 修改pg_hba.conf文件 打开pg_hba.conf文件,在文件末尾添加一行内容: host database_name user_name IP_address authentication_me…

    C 2023年5月22日
    00
  • C语言链表实现简单图书管理系统

    C语言链表是一种常用的数据结构,通过链表可以实现一些比较复杂的数据管理系统。本篇攻略将讲解如何使用C语言链表实现一个简单的图书管理系统。整个系统的实现分为以下几步: 定义图书数据结构。在本例中,我们需要使用结构体来存储每一本图书的信息,如图书编号、图书名称、图书作者等。 struct Book { int id; char title[50]; char a…

    C 2023年5月23日
    00
  • C++游戏教程基本技巧之随机化详解

    《C++游戏教程基本技巧之随机化详解》是一篇针对C++游戏开发者的教程,旨在讲解如何使用随机数来增加游戏的趣味性和难度。该教程主要包含以下几个方面的内容: C++随机数生成器的介绍 随机数应用在游戏中的场景 随机数生成的技巧和注意事项 随机数实现的两个示例 C++随机数生成器的介绍 C++的标准库中提供了一个随机数生成器库,名为rand()。该函数可以生成一…

    C 2023年5月22日
    00
  • C语言错误使用sizeof操作符

    介绍C语言中错误使用sizeof操作符的完整使用攻略。 什么是 sizeof 操作符 sizeof是C语言中的一元操作符,用于计算某个数据类型所占内存的字节数。其用法如下: sizeof(type) 其中 type 可以是任何C语言中的数据类型,包括基本数据类型、数组、结构体、联合体或指针等。 错误用法示例 sizeof 数组 有些C语言开发者会尝试使用si…

    C 2023年5月9日
    00
  • 淘宝C店策划 如何策划一个月入3万元的淘宝C店

    淘宝C店策划如何达到一个月3万元的销售额 淘宝C店是一个可以自主开设店铺的平台,为了在淘宝平台上达到月入3万元的销售额,需要进行以下策划。 1.产品策略 找到适合受众的产品:通过淘宝平台的搜索工具找到热门、富有竞争力的产品,需要考虑到目标受众的消费习惯和需求,挖掘消费者的无形需求,分析受众市场分布和需求热点,最终确定销售的产品。 精准定位产品差异化:找到适合…

    C 2023年5月23日
    00
  • C语言中的正则表达式使用示例详解

    C语言中的正则表达式使用示例详解 正则表达式是一种通用的文本匹配模式,可以在C语言中用来进行字符串的匹配和处理。C语言提供了regex库来支持正则表达式的使用。接下来,将为您详细讲解C语言中正则表达式的使用,包括正则表达式语法、函数调用和示例说明。 正则表达式语法 正则表达式语法是一组规则,用于描述文本模式匹配的方式。在C语言中,正则表达式的语法由一些特殊字…

    C 2023年5月23日
    00
  • iPhone6c什么时候上市?苹果iPhone6c报价多少钱?

    iPhone 6c 介绍 苹果公司于2015年推出了iPhone 6和iPhone 6 Plus,这两款手机都采用了全新的设计风格,并迅速得到消费者的喜爱。接着,苹果又推出了iPhone SE,这款手机采用了iPhone 5s的外观设计但换装了A9处理器,提供了更好的性能和更低的价格。而对于iPhone 6的后续产品,苹果一直没有推出iPhone 6c,这让…

    C 2023年5月22日
    00
  • C++实现DES加密算法实例解析

    C++实现DES加密算法实例解析 简介 DES(Data Encryption Standard)算法是一种对称加密算法,通常用于保护数据的机密性。与其他加密算法相比,它的优势在于速度快,代码简单,实现成本较低,因此在许多安全应用中广泛使用。 本教程将会详细介绍如何使用C++语言实现DES加密算法,并提供两个示例说明,使读者可以快速掌握DES加密算法的使用方…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部