现在很多业务开发,尤其是互联网应用,绝大多数采用的是Java,这个不仅仅是Java语言的流行,还有很多分布式框架都是采用的Java。而传统的C/C++开发更为偏向底层等高效率基础功能和服务开发。
随着对象,资源和SOA架构的深入人心,其实C也有很多编程技巧能够完成这些更为高级的语言所能完成的任务,只是可能需要一些技巧。这里我们就谈谈函数默认实现和用户自定义实现。
这里介绍几种方式,供大家实现时参考:
==》Reference code(示例代码)
==》Pointer operation(指针操作)
==》Weak & Strong Alias(强弱别名)
这个比较简单,也就是开发代码的时候将一段代码以示例的方式写好。然后用户直接复制源代码,然后进行修改,实现用户的自定义方式。
优点:最为直接的一种代码Demo方式,开发人员很容易接受
缺点:开发人员需要对示例代码进行检查,至少需要review代码,确保正确性。
实现方法通过指针操作进行定位函数入口,当函数指针未被赋值就是原默认实现方法,当用户对其进行赋值,即运行用户自定义方法。
优点:常用方法,已经被广泛使用,尤其是Linux内核及驱动开发,基本采用这种方式。
缺点:指针操作要小心。
这个是编译链接的时候进行的操作,类似于对象默认方法,当没有自定义的方法时,链接到默认的方法实现,如果有实现方法(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. weakref weakref ("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.
#include <stdio.h> void fun() { printf("weak test\n"); } void fun() __attribute__ ((weak));
#include <stdio.h> void fun() { printf("strong test\n"); }
# 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_weak weak test # ./test strong test
我们对上述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
# nm -s libtest_weak.a Archive index: fun in libtest_weak.o libtest_weak.o: 0000000000000000 W fun U puts
# nm -s libtest_strong.a Archive index: fun in libtest_strong.o libtest_strong.o: 0000000000000000 T fun U puts
修改源文件分别如下所示:
libtest_strong.c
#include <stdio.h> void fun() { printf("libtest_strong test\n"); }
#include <stdio.h> void fun() { printf("libtest_weak test\n"); } void fun() __attribute__ ((weak));
#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
# 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_libweak test_strong.c test # ./test_libweak_strong test_strong.c test
# 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 here collect2: error: ld returned 1 exit status # ./test_strong_libstrong test_strong.c test # ./test_libstrong_strong -bash: ./test_libstrong_strong: No such file or directory
# 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_libweak test_weak.c test # ./test_libweak_weak libtest_weak test
# 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_libstrong test_weak.c test # ./test_libstrong_weak libtest_strong test
# 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_strong test_strong.c test # ./test_strong_weak test_strong.c test
# 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 here collect2: error: ld returned 1 exit status
# 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_weak2 test_weak.c test #./test_weak2_weak test_weak2.c test
因此,采用这种方式进行默认方法操作,通过不同的链接逻辑,可以隐藏很多实现方式。
【1】GCC使用手册