C 语言静态库的一些特性总结

一、静态库按 .o 为最小单位连接到程序,如果某个 .o 中的所有符号都没有被引入则这个 .o 不会被连接,反之 .o 中只要有一个符号被引入则链接整个 .o 。可以做一个例子来验证一下。

        构建一个静态库,包含两个 .c 文件,libtest.c 和 libtest2.c。libtest.c 中包含三个函数:lib_func1()、lib_func2()、lib_func3()。

#include <stdio.h>

void lib_func1 (void)
{
    printf("lib_func call1!\n");
}

void lib_func2 (void)
{
    printf("lib_func call2!\n");
}

void lib_func3 (void)
{
    printf("lib_func call3!\n");
}

        libtest2.c 中包含一个函数:lib_func4 ()

#include <stdio.h>

void lib_func4 (void)
{
    printf("lib_func call4!\n");
}

        APP 链接此静态库,定义与静态库重名的函数 lib_func2(),并在程序中调用 lib_func1() 和 lib_func1()。APP 程序如下:

#include <stdio.h>

void lib_func2 (void)
{
    printf("app: lib_func call2!\n");
}

extern void lib_func1(void);
extern void lib_func2(void);
extern void lib_func3(void);
extern void lib_func4(void);

int main (int argc, char **argv)
{
    lib_func1();
    lib_func4();

    return  (0);
}

        此时编译程序会报重复定义错误,因为程序中调用的 lib_func1() 与 lib_func4() 分别在 libtest.o 和 libtest2.o 中,因此链接时会包含这两个 .o。这就导致 libtest.o 中的符号 lib_func2() 被导入,并与 APP 中定义的 lib_func2() 重复,因此报重复定义错误。

         此时删除 APP 中调用 lib_func1() 的位置编译即可通过。因为 APP 中没有调用任何 libtest2.o 中的符号,因此链接时不会连接 libtest2.o,也就不会导入符号 lib_func2(),因此不会与 APP 中定义的 lib_func2() 冲突。

二、若在链接静态库时希望无论是否调用,均链接所有的 .o 可以使用链接参数 -Wl,--whole-archive 和 -Wl,--no-whole-archive(这是链接参数,gcc 不识别,需要通过 gcc 转到 ld,因此需要加 -Wl 前缀)。

-Wl,--whole-archive 此定义之后的静态库全部完整链接

-Wl,--no-whole-archive 取消静态库全部完整链接

使用:

LOCAL_DEPEND_LIB := \

-Wl,--whole-archive \

-l:lib2.a

-Wl,--no-whole-archive

三、如果静态库中某个 .o 的所有符号均在 APP 中定义,则不会链接此 .o。编译时也不会报重复定义错误。我们稍微修改一下上述的 APP,把 lib_test.o 中其他的两个函数 lib_func1() 和 lib_func3() 全部定义一遍,编译不报错。代码如下:

#include <stdio.h>

void lib_func1 (void)
{
    printf("app: lib_func call1!\n");
}

void lib_func2 (void)
{
    printf("app: lib_func call2!\n");
}

void lib_func3 (void)
{
    printf("app: lib_func call3!\n");
}

extern void lib_func1(void);
extern void lib_func2(void);
extern void lib_func3(void);
extern void lib_func4(void);

int main (int argc, char **argv)
{
    lib_func1();
    lib_func2();
    lib_func4();

    return  (0);
}

        运行结果表明 lib_func1() 与 lib_func2() 执行的确实是 APP 中定义的函数:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C程序设计语言C语言精典版本 目 录 译者序 序 第1版序 前言 第1章 基本概念 1.1 入门 1.2 变量与算术表达式 1.3 for语句 1.4 符号常量 1.5 字符输入输出 1.5.1 文件复制 1.5.2 字符计数 1.5.3 行计数 1.5.4 单词计数 1.6 数组 1.7 函数 1.8 变元—按值调用 1.9 字符数组 1.10 外部变量与作用域 第2章 类型、运算符与表达式 2.1 变量名 2.2 数据类型与大小 2.3 常量 2.4 说明 2.5 算术运算符 2.6 关系运算符与逻辑运算符 2.7 类型转换 2.8 加一与减一运算符 2.9 按位运算符 2.10 赋值运算符与赋值表达式 2.11 条件表达式 2.12 运算符优先级与表达式求值次序 第3章 控制流 3.1 语句与分程序 3.2 if-else语句 3.3 else-if语句 3.4 switch语句 3.5 while与for循环语句 3.6 do-while循环语句 3.7 break语句与continue语句 3.8 goto语句与标号 第4章 函数与程序结构 4.1 函数的基本知识 4.2 返回非整数值的函数 4.3 外部变量 4.4 作用域规则 4.5 头文件 4.6 静态变量 4.7 寄存器变量 4.8 分程序结构 4.9 初始化 4.10 递归 4.11 C预处理程序 4.11.1 文件包含 4.11.2 宏替换 4.11.3 条件包含 第5章 指针与数组 5.1 指针与地址 5.2 指针与函数变元 5.3 指针与数组 5.4 地址算术运算 5.5 字符指针与函数 5.6 指针数组与指向指针的指针 5.7 多维数组 5.8 指针数组的初始化 5.9 指针与多维数组 5.10 命令行变元 5.11 指向函数的指针 5.12 复杂说明 第6章 结构 6.1 结构的基本知识 6.2 结构与函数 6.3 结构数组 6.4 结构指针 6.5 自引用结构 6.6 查找表 6.7 类型定义 6.8 联合 6.9 位字段 第7章 输入与输出 7.1 标准输入输出 7.2 格式输出—printf函数 7.3 变长变元表 7.4 格式输入—scanf函数 7.5 文件访问 7.6 错误处理—stderr和exit函数 7.7 行输入输出 7.8 其他函数 7.8.1 字符串处理函数 7.8.2 字符类测试和转换函数 7.8.3 ungetc函数 7.8.4 命令执行函数 7.8.5 存储管理函数 7.8.6 数学函数 7.8.7 随机数发生器函数 第8章 UNIX系统界面 8.1 文件描述符 8.2 低级I/O—read和write系统调用 8.3 open、creat、close和unlink系统调用 8.4 随机访问—lseek系统调用 8.5 实例—fopen和getc函数的一种实现 方法 8.6 实例—目录显示 8.7 实例—存储分配程序 附录A 参考手册 A.1 引言 A.2 词法规则 A.3 语法符号 A.4 标识符的含义 A.5 对象和左值 A.6 转换 A.7 表达式 A.8 说明 A.9 语句 A.10 外部说明 A.11 作用域与连接 A.12 预处理 A.13 语法 附录B 标准库 B.1 输入与输出:<stdio.h> B.2 字符类测试:<ctype.h> B.3 字符串函数:<string.h> B.4 数学函数:<math.h> B.5 实用函数:<stdlib.h> B.6 诊断:<assert.h> B.7 变量变元表:<stdarg.h> B.8 非局部跳转:<setjmp.h> B.9 信号处理:<signal.h> B.10 日期与时间函数:<time.h> B.11 由实现定义的限制:<limits.h>和 <float.h> 附录C 变更小结 序自从1978年《C程序设计语言》出版以来,计算机界经历了一场革命。大型计算机变得更大;而个人计算机的能力可以和十年前的主流计算机相媲美。在这段时间中,C语言也在悄悄地改变,并且早已超出了仅仅作为UNIX操作系统的语言的范畴。 C的适用范围的扩大、在这些年中语言的改变和各个组织开发的超出其预定内容的编译器,所有这一切要求对C语言有一个比本书第1版更精确和更新的定义。在1983年,美国国家标准协会(ANSI)成立了一个委员会,它的目标是产生“一个无二义性的、独立于机器的C语言的定义”,同时仍保持其精髓。其结果就是C的ANSI标准。此标准规范了一些在本书第1版中提示过但没有描述的结构,特别是结构赋值和枚举。它提供了一种新的函数声明的形式,允许在使用中对函数的定义进行交叉检查。它说明了一个标准库和一个完成输入输出、内存管理和字符串操作等类似任务的函数集扩充。此标准明确地说明了原始定义没有指出的一些特性的行为。同时,此标准还明确地说明了语言中的哪些部分依然依赖于机器。《C程序设计语言》的第2版描述的是ANSI标准定义的C语言。尽管我们已经指出语言中的多种革新,但我们还是决定不用新的形式来写。对于大部分内容并没有多大的差别,最明显的改变是新形式的函数声明和定义。现代编译器已能支持此标准的大部分特性。我们尽力保持本书第1版的简洁性。C不是一个大型语言,也不需要一本很厚的书来描述。我们改进了对典型特性的阐述,如指针,它是C程序设计的中心。我们对以前的例子进行了提炼,并在几章中增加了新的例子。例如,我们用程序来处理复杂的声明,这些程序将声明转换为单词或反之。像以前一样,所有例子的文本都以机器可读的形式直接经过测试。附录A是参考手册,不是标准,但我们的目的是希望用较少的篇幅表述标准的要点。它是要对于程序员来说容易理解,而不是提供给编译器实现者的定义—这正是标准承担的角色。附录B是对标准库提供的功能的总结。附录C是对以前版本的变动的小结。就像我们在第1版序中所说的,“当对C的经验增加时它显得很好用”。经过十几年的实践,我们仍然这么认为。我们希望这本书能帮助你学习并使用好C语言。非常感谢那些帮助我们完成本书这一版的朋友们。Jon Bentley、Doug Gwyn、Doug McIlroy、Peter Nelson和Rob Pike几乎对本书手稿的每一页都提出了建议。我们非常感谢Al Aho、Dennis Allison、Joe Campbell、G.R.Emlin、Karen Fortgang、Allen Holub、Andrew Hume、Dave Kristol、John Linderman、Dave Prosser、Gene Spafford和Chris Van Wyk,他们仔细地阅读了本书。我们也收到了来自Bill Cheswick、Mark Kernighan、Andy Koenig、Robin Lake、Tom London、Jim Reeds、Clovis Tondo和Peter Weinberger的有益的建议。Dave Prosser回答了很多关于ANSI标准的细节问题。我们广泛地使用了Bjarne Stroustrup的C++的翻译程序来部分测试我们的程序。Dave Kristol为我们提供了一个ANSI C编译器进行最终测试。Rich Drechsler帮助我们进行了排版。诚挚地感谢每一个人。 Brian W. Kernighan Dennis M. Ritchie
### 回答1: sysy语言是一种面向过程的编程语言,它专门用于教育目的,旨在帮助初学者快速入门计算机编程。sysy语言具有简单易懂的语法和丰富的库函数,可以实现各种常见的编程任务。 与sysy语言紧密相关的是它的运行时库。运行时库是一组用于支持编程语言运行的软件组件,它提供了必要的工具和功能,使得sysy语言能够在计算机上执行。 sysy语言的运行时库包含了各种重要的功能,例如内存管理、输入输出处理、字符串操作和数学计算等。它提供了易于使用的函数和接口,方便程序员进行开发,并且隐藏了很多底层细节。 例如,sysy语言的运行时库中的内存管理功能可帮助程序员管理内存分配和释放,确保程序运行时的内存使用是安全和高效的。输入输出处理功能则可以让程序从键盘中读取用户输入,并向屏幕输出结果。字符串操作和数学计算功能可以帮助开发者对字符串进行操作和进行基本的数值运算。 总之,sysy语言与它的运行时库是为初学者设计的一套完整的开发环境。通过sysy语言,初学者可以快速掌握基本的编程概念和技能,并通过其丰富的运行时库函数,实现各种常见的编程任务。同时,sysy语言的运行时库提供了很多底层功能的封装,方便程序员进行开发,从而加快开发速度和提高开发效率。 ### 回答2: sysy语言是中国科学技术大学开发的一种静态类型的编程语言,其目标是为了研究人员和学生提供一个高效、易用的计算机编程环境。sysy语言是C语言的一个子集,它剥离了一些复杂的特性,使得编写代码更加简洁和易懂。 运行时库是指在程序运行过程中需要用到的一些函数、过程以及数据结构等代码库。sysy语言的运行时库是为了支持sysy语言的编程环境而设计的。它提供了一系列的库函数和运行时支持,以帮助程序员更方便地开发和调试代码。 sysy语言的运行时库包括了常见的库函数,如数学库、字符串处理库等。它还提供了一些针对sysy语言特性的运行时支持,比如对于函数调用、变量声明和作用域的处理等。运行时库可以提供一些基本的运行时支持,避免程序员手动编写底层的代码,减少了开发时间和代码复杂性。 除此之外,sysy语言的运行时库还提供了一些错误处理的机制,使得程序在出现错误时能够进行合理的处理。例如,它可以提供异常处理机制,使得程序能够在出现异常情况时进行恢复或报告错误。 总之,sysy语言与运行时库紧密配合,为程序员提供了一种高效、易用的编程环境。通过使用sysy语言和其运行时库,开发人员可以更加专注于解决问题,提高编程效率和代码质量。 ### 回答3: sysy语言是一种面向学术研究的静态类型编程语言,它被设计用于在系统软件开发和编译原理教学中。sysy语言的语法结构简单明了,易于理解和学习。它具有静态类型检查,从而能够在编译时发现潜在的类型错误,提高了代码的可靠性和执行效率。 sysy语言的运行时库是负责提供运行时环境的支持库。它包含了一系列的函数和数据结构,使得sysy语言编写的程序能够在特定的操作系统或者硬件平台上正确运行。运行时库负责提供与底层系统交互的接口,如文件操作、内存管理、线程管理等。同时,运行时库还负责实现sysy语言中一些高级的功能特性,如动态内存分配、异常处理、多线程调度等。 sysy语言和运行时库之间存在着密切的关联。sysy语言的程序在编译时会依赖于运行时库提供的函数和数据结构,以完成各种任务。同时,运行时库能够有效地支持sysy语言中的高级特性,提供更为丰富的功能,并为开发者提供更方便的编程接口。sysy语言和运行时库的良好配合,使得开发者能够更加轻松地开发出高效可靠的系统软件。 总之,sysy语言是一种面向学术研究的编程语言,而运行时库是sysy语言的重要组成部分,负责提供运行时环境的支持和实现高级特性。它们之间的协作可以有效地提高编程效率和代码可靠性,是系统软件开发中不可缺少的一部分。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

stone8761

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值