C中的强符号与弱符号

作用域

c语言的作用域有两种,代码块作用域和文件作用域。代码块作用域是指由花括号限定的作用域,花括号以外的作用域就是文件作用域。这里指的花括号可以是函数的花括号,if,while,for,namespace的花括号,遵循的基本规则是花括号以里可以看到本花括号以外的东西,但是相反则不可以。

int main()
{
    int y=4;
    {
        int x=3;
        y=5;
    }
    x=2;
}

比如这段代码编译器会报错“未声明的标识符x”。

在代码块以外生命的函数或者变量属于文件作用域,当未加限定时,他们是全局可见的。即可以在别的文件中去访问他们,当然需要在使用他们的文件中加入对它们的声明。我们可以使用static来限定文件作用域中的变量和函数的可见范围,如此做可以让他们只在定义他们的文件中可见。

另外对代码块作用域正确与否的检测是在编译阶段完成的,由于编译阶段只能看到本文件的内容,所以文件作用域中的变量是否在其他文件中正确定义编译器是不得而知的,如果使用的变量在别的文件中并没有定义,那么在连接的时候会报错。

强符号和弱符号

明确一点,强符号和弱符号是对链接而言的,这两个概念一般只会被用在文件定义域中。C/C++允许在文件定义域中定义两个同样名字的变量,当然这其中需要遵循一定的规则。

  • 当出现多个强符号在文件定义域中时,报错。
  • 当只有一个强符号时,选取强符号的值。
  • 当没有强符号时,选择其中占用空间较大的弱符号。(这条性质我一直没有找到合适的方法验证)

对于C/C++而言,编译器默认函数已初始化的全局变量为强符号,而未初始化的全局变量为弱符号。开发者可以对符号进行指定,使用__attribute__((weak))来将一个强符号转变为弱符号。

int __attribute__((weak)) x=0;

看到这里可能会让人一头雾水,不明白这样的性质有什么实际价值。其实这个性质最大的作用是用在函数库中,我们可以把函数库中的某个函数定义为弱符号,这样用户可以在自己的文件中重新定义一个重名的函数去替代库函数中的函数,因为如果不加以刻意声明,用户定义的属于强符号,遵循上边的规则,链接器会优先使用强符号。我们通过一个例子来感受一下。

test.c

#include<stdio.h>
void __attribute__((weak)) weak_func(void)
{
    printf("defualt weak func is running!\n");
}
void test_func(void)
{
    weak_func();
}

main.c

#include<stdio.h>
extern void test_func(void);
void weak_func(void)
{
    printf("custom strong func override!\n");
}
int main ()
{
    test_func();
}

当我们把main.c中的weak_func注释掉

这种特性让我们很方便的对一个库的功能进行剪裁和组合。

猜你喜欢

转载自blog.csdn.net/qq_33113661/article/details/89601430