【C语言】函数默认实现和用户自定义实现编程方法 -- 【weak, strong alias】

来源:互联网 发布:如何提高雅思写作 知乎 编辑:程序博客网 时间:2024/06/07 20:26

现在很多业务开发,尤其是互联网应用,绝大多数采用的是Java,这个不仅仅是Java语言的流行,还有很多分布式框架都是采用的Java。而传统的C/C++开发更为偏向底层等高效率基础功能和服务开发。


随着对象,资源和SOA架构的深入人心,其实C也有很多编程技巧能够完成这些更为高级的语言所能完成的任务,只是可能需要一些技巧。这里我们就谈谈函数默认实现和用户自定义实现。


函数默认实现和用户自定义实现

这里介绍几种方式,供大家实现时参考:

==》Reference code(示例代码)

==》Pointer operation(指针操作)

==》Weak & Strong Alias(强弱别名)


1.Reference code(示例代码)

这个比较简单,也就是开发代码的时候将一段代码以示例的方式写好。然后用户直接复制源代码,然后进行修改,实现用户的自定义方式。

优点:最为直接的一种代码Demo方式,开发人员很容易接受

缺点:开发人员需要对示例代码进行检查,至少需要review代码,确保正确性。


2.Pointer operation(指针操作)

实现方法通过指针操作进行定位函数入口,当函数指针未被赋值就是原默认实现方法,当用户对其进行赋值,即运行用户自定义方法。

优点:常用方法,已经被广泛使用,尤其是Linux内核及驱动开发,基本采用这种方式。

缺点:指针操作要小心。


3.Weak & Strong Alias(强弱别名)

这个是编译链接的时候进行的操作,类似于对象默认方法,当没有自定义的方法时,链接到默认的方法实现,如果有实现方法(Strong Alias)的时候就采用强别名。

优点:默认方法不用关心,只要关心需要实现的方法。

缺点:默认实现方法被隐藏(如果不注意的话),更像高级应用,只开发自己关心的内容,其他都由框架完成。


由于前两种方式大家都较为熟悉,这里就简单介绍下Weak & Strong Alias的基本依据和应用方法。


Weak & Strong Alias的基本依据

GCC手册中关于Weak & Strong Alias的介绍如下,大意就是强属性链接权限高于弱属性,如果一个函数符号优先链接的是强属性符号而非弱属性。这就是这里将会使用demo来介绍给大家的这个特性。

weak    The weak attribute causes the declaration to be emitted as a weak symbol rather than a global. This is primarily useful in defining library functions which can be overridden in user code, though it can also be used with non-function declarations. Weak symbols are supported for ELF targets, and also for a.out targets when using the GNU assembler and linker.weakrefweakref ("target")    The weakref attribute marks a declaration as a weak reference. Without arguments, it should be accompanied by an alias attribute naming the target symbol. Optionally, the target may be given as an argument to weakref itself. In either case, weakref implicitly marks the declaration as weak. Without a target, given as an argument to weakref or to alias, weakref is equivalent to weak.              static int x() __attribute__ ((weakref ("y")));              /* is equivalent to... */              static int x() __attribute__ ((weak, weakref, alias ("y")));              /* and to... */              static int x() __attribute__ ((weakref));              static int x() __attribute__ ((alias ("y")));             A weak reference is an alias that does not by itself require a definition to be given for the target symbol. If the target symbol is only referenced through weak references, then the becomes a weak undefined symbol. If it is directly referenced, however, then such strong references prevail, and a definition will be required for the symbol, not necessarily in the same translation unit.    The effect is equivalent to moving all references to the alias to a separate translation unit, renaming the alias to the aliased symbol, declaring it as weak, compiling the two separate translation units and performing a reloadable link on them.    At present, a declaration to which weakref is attached can only be static. 


Weak & Strong Alias自定义函数验证

首先,建一个libtest_weak.c,实现默认fun方法输出“weak test”

#include <stdio.h> void fun(){    printf("weak test\n");} void fun() __attribute__ ((weak));

然后,建一个test_strong.c,用户自定义fun方法输出“strong test”

#include <stdio.h> void fun(){    printf("strong test\n");}

接下来,编译默认weak实现库和测试weak和stong的可执行文件

# gcc -c libtest_weak.c# ar crv libtest_weak.a libtest_weak.o# gcc -o test_weak main.c libtest_weak.a# gcc -o test main.c test_strong.c libtest_weak.a

最后,执行输出结果

# ./test_weakweak test# ./teststrong test

从上述对比结果,我们可以看出,没有strong symbol的时候,链接器将fun链接到了weak symbol上,输出“weak test”,当我们增加test_strong.c实现了fun函数后,链接器就链接了strong symbol。

Weak & Strong Alias库打包差异

我们对上述libtest_weak.c和test_strong.c(修改文件名为libtest_strong.c)进行库打包

# gcc -c libtest_weak.c# ar crv libtest_weak.a libtest_weak.o<pre name="code" class="plain"># gcc -c libtest_strong.c# ar crv libtest_strong.a libtest_weak.o

分析.a文件,可以看到fun符号,在libtest_weak.a中是“W”,而在libtest_strong.a中是“T”,链接器将会优先考虑“T”

# nm -s libtest_weak.aArchive index:fun in libtest_weak.olibtest_weak.o:0000000000000000 W fun                 U puts

# nm -s libtest_strong.aArchive index:fun in libtest_strong.olibtest_strong.o:0000000000000000 T fun                 U puts

库函数、strong、weak符号导致的问题


修改源文件分别如下所示:

libtest_strong.c

#include <stdio.h> void fun(){    printf("libtest_strong test\n");}

libtest_weak.c

#include <stdio.h> void fun(){    printf("libtest_weak test\n");} void fun() __attribute__ ((weak));

test_strong.c和test_strong2.c

#include <stdio.h> void fun(){    printf("test_strong.c test\n");}
test_weak.c

#include <stdio.h> void fun(){    printf("test_weak.c test\n");}void fun() __attribute__ ((weak));

test_weak2.c

#include <stdio.h> void fun(){    printf("test_weak2.c test\n");}void fun() __attribute__ ((weak));

对代码进行组合编译链接:

# gcc -c libtest_weak.c# ar crv libtest_weak.a libtest_weak.o# gcc -c libtest_strong.c# ar crv libtest_strong.a libtest_strong.o

.c文件中存在strong符号,优先链接

# gcc -o test_strong_libweak main.c test_strong.c libtest_weak.a# gcc -o test_libweak_strong main.c libtest_weak.a test_strong.c # ./test_strong_libweaktest_strong.c test# ./test_libweak_strongtest_strong.c test

.c先链接,strong符号与.a冲突,以.c为准

.a先链接,strong符合与.c冲突,链接失败

# gcc -o test_strong_libstrong main.c test_strong.c libtest_strong.a# gcc -o test_libstrong_strong main.c libtest_strong.a test_strong.c /tmp/cceiDAEw.o: In function `fun':test_strong.c:(.text+0x0): multiple definition of `fun'libtest_strong.a(libtest_strong.o):libtest_strong.c:(.text+0x0): first defined herecollect2: error: ld returned 1 exit status# ./test_strong_libstrongtest_strong.c test# ./test_libstrong_strong-bash: ./test_libstrong_strong: No such file or directory

.a和.c哪个先链接,weak符号先起作用

# gcc -o test_weak_libweak main.c test_weak.c libtest_weak.a# gcc -o test_libweak_weak main.c libtest_weak.a test_weak.c# ./test_weak_libweaktest_weak.c test# ./test_libweak_weaklibtest_weak test

.c先链接,weak符号不weak,可以覆盖.a中的strong和weak符号

# gcc -o test_weak_libstrong main.c test_weak.c libtest_strong.a# gcc -o test_libstrong_weak main.c libtest_strong.a test_weak.c# ./test_weak_libstrongtest_weak.c test# ./test_libstrong_weaklibtest_strong test

.c编译链接过程,strong符号可以覆盖weak符号

# gcc -o test_weak_strong main.c test_weak.c test_strong.c# gcc -o test_strong_weak main.c test_strong.c test_weak.c # ./test_weak_strongtest_strong.c test# ./test_strong_weaktest_strong.c test

.c编译链接过程,strong符号重复,链接失败

# gcc -o test_strong_strong main.c test_strong.c test_strong2.c/tmp/cc3c8J5H.o: In function `fun':test_strong2.c:(.text+0x0): multiple definition of `fun'/tmp/ccy49Mpb.o:test_strong.c:(.text+0x0): first defined herecollect2: error: ld returned 1 exit status

.c编译链接过程,先链接的weak符号优先考虑

# gcc -o test_weak_weak2 main.c test_weak.c test_weak2.c# gcc -o test_weak2_weak main.c test_weak2.c test_weak.c# ./test_weak_weak2test_weak.c test#./test_weak2_weaktest_weak2.c test


因此,采用这种方式进行默认方法操作,通过不同的链接逻辑,可以隐藏很多实现方式。


参考资料

【1】GCC使用手册


0 0