C标准库-Bionic


Bionic libc 是一种 C 标准函数库(包含libc、libdl、libm与libpthread),是由 Google 公司所开发的自由软件,用于 Android 嵌入式系统上,采用 BSD 三类许可协议并运行于Linux kernel上。谷歌希望用它来取代 glibc,它的发展目标是达到轻量化以及高运行速度。植根于 BSD 的 libc 体系,但与典型的 BSD C 函式库不同的地方在于,Bionic 不依赖 BSD kernel,也无须使用 GNU C 函式库(glibc)的‘GNU较宽松公共许可协议’。
它是Android平台为了使用C/C++进行原生应用程序开发所有提供的POSIX标准C库;是Google为Android操作系统提供的BSD标准C库的衍生库;同时它也是专门为移动计算而精心设计的,针对移动设备上有限的CPU周期和可用内存进行了裁剪以提高工作效率。尽管其是C标准库,但是它不以任何方式与其它C库二进制兼容。也就是说Bionic和其它C库不兼容,无法进行交叉编译和相互引用,它是连接Android系统和Linux系统内核的纽带。其包含了系统中最基本的lib库,包括libc,libm,libdl,libstd++,libthread_db,以及Android特有的链接器linker。
Bionic提供了C标准库,类型定义,函数和少数Android特有的特性。主要功能可以概括如下:
内存管理
文件输入输出
字符串操作
数学函数
日期和时间
进程控制
信号处理
网络套接字
多线程
用户和组
系统配置
命名服务切换
GPL世界和非GPL世界的分界线在于一个叫做 Bionic Libc 的类库。其关键之处在于如果 Bionic Libc 受到内核 GPL 的“感染”,将会波及非 GPL 的用户空间的各个模块。谷歌使用Bionic库主要因为有以下三点考量:
1.谷歌没有使用Linux的GUN Libc,很大一部分原因是因为GNU Libc的授权方式是GPL授权协议有限制,因为一旦软件中使用了GPL的授权协议,该系统所有代码必须开源。
2.谷歌在BSD的C库上的基础上加入了一些Linux特性从而生成了Bionic。该名字的来源就是BSD和Linux的混合。而且不受限制的开源方式,所以在现代的商业公司中比较受欢迎。
3.另外就是因为性能的原因,因为Bionic的核心设计思想就是"简单",所以其中去掉了很多高级功能。这样Bionic库仅为200K左右,是GNU版本体积的一半,这意味着更高的效率和低内存的使用,同时配合经过优化的Java VM Dalvik才可以保证高的性能。
知乎的博睿数据对此有比较详细的叙述:
在 2008 年 Google IO大会上,一份著名的 PPT:“Android Anatomy And Physiology” 讲到 Android 使用 Bionic Libc 类库替换Linux常用的 Gnu glibc ,其中一个主要原因是 “We want to keep GPL out of user-”。(这其实有点难理解,毕竟 Gnu glibc 采用的是 LGPL 而非 GPL,并基于上文 GPL 第一点的讨论,使用系统调用的程序不再被视为 Linux 内核的衍生产品,并不需要遵循 GPL) 。Bionic Libc 充满着非议,Bionic Libc 拷贝内核头文件的行为,并在源码中声明的版权信息均遭到了 侵犯 Linux 内核 GPL 约束 ” 的质疑。
这是 Bionic 头文件的版权信息,许多人认为是非法的:“This header was automatically generated from a Linux kernel header of the same name, to make information necessary for userspace to call into the kernel available to libc. It contains only constants, structures, and macros generated from the original header, and thus, contains no copyrightable information.”
头文件由Linux内核的同名头文件自动生成,用来获取完成用户空间系统调用的必要的信息。它只包含原头文件中的常数、结构和宏定义,因此,不包含版权信息。不管如何,从目前的情况看,让 GPL 止步于内核空间的做法是成功的,并已经得到很大一部分内核开发者的认同。James Bottomley,Linux SCSI 子系统的维护者在 2011年 LinuxCon 大会日本站上谈到 Android 的商业成功与 GPL 恐惧的时候说:We should also design more “bright line” systems which make the question of GPL compliance clear. The kernel’s user-space ABI is one such system; developers know that user-space code is not considered to be derived from the kernel. Making the boundary easy to understand helps to make the GPL less scary.
在遵守 GPL 的问题上,我们必须澄清一些界线。内核的用户空间 ABI(应用二进制接口)就是一种 GPL 的作用边界,能让开发者意识到用户空间的代码,不被定性为内核的衍生产品,如果 GPL 的界线清晰而易懂,可以帮助大家消除对 GPL 的恐惧。
Android 的发展离不开硬件设备厂商的支持,硬件设备厂商最关注的是 Linux 驱动的 GPL 约束问题,公开驱动程序源代码将会泄漏设备的硬件规格和泄漏核心知识产权,这是硬件厂商 GPL 恐惧的缘由。Google 不遗余力的为硬件设备厂家排忧艰难,保驾护航。上文提到的 “Android Anatomy And Physiology”,文中清晰的讲到 Android 在用户空间与内核空间之间存在着硬件抽象层 HAL(Hardware Abstraction Layer),HAL 类库本质上一种用户空间的驱动,其中的主要用途之一:规避 GPL。
Bionic 具有诸多显著优势。首先它经过了严格的优化,以适应移动设备的资源限制和性能要求。在内存管理、线程调度等方面表现出色,能够确保 Android 应用程序在不同硬件平台上都能高效运行。这个标准库提供了丰富的功能,涵盖了字符串处理、数学运算、文件操作等多个方面。例如,它提供了高效的字符串拼接和查找函数,以及快速的数学计算函数。在文件操作方面,Bionic 支持多种文件系统,并提供了安全可靠的文件读写功能。需要注意的是,通常在 Android 开发中,会使用 Java 或 Kotlin 语言进行应用开发,较少直接使用 Bionic 库中的函数进行编程。但在 Android 的底层开发或使用 NDK(Native Development Kit)进行 C/C++ 开发时,可能会涉及到使用 Bionic 库的函数。
Bionic与Glibc
Bionic当前支持ARM、x86和MIPS执行集,理论上可以支持更多,但是需要做些工作,ARM相关的代码在目录arch-arm中,x86相关代码在arch-x86中,mips相关的代码在arch-mips中。Android使用Bionic而不使用Glibc的最主要原因:
1.有限的空间和存储
2.较低的CPU速度
3.不完全开源
Bionic的优势
1.去除头文件的相关内容,占用更小的存储
2.规避GPL,上文有述
3.占用更小的空间,Bionic 大约 200KB, Glibc 400KB,(去除臃肿的代码以及不必要的功能)
4.低速CPU优化,主要源于对pthread的优化,这也是一个缺点,因为他只专门为低时钟频率的 CPU设计
Bionic的限制和缺点
异常处理、STL 不支持
Pthreads
Cancellation 不支持
pthread_once() 不支持 初始化函数和初始化函数调用fork()的异常处理
pthread_atfork()函数 不支持
不支持区域和宽字符,程序员应该使用Unicode
用户账户相关功能,没有真正实现,这是目前只支持单用户的原因
Bionic的内存管理器:dlmalloc
dlmalloc是一个十分流行的内存分配器。dlmalloc位于bionic/libc/upstream-dlmalloc下,只有一个C文件malloc.c。其原理大致如下:
(1)、dlmalloc内部是以链表的形式将"堆"的空闲空间根据尺寸组织在一起。分配内存时通过这些链表能快速地找到合适大小的空闲内存。如果不能找到满足要求的空闲内存,dlmalloc会使用系统调用来扩大堆空间。
(2)、dlmalloc内存块被称为"trunk"。每块大小要求按地址对齐(默认8个字节),因此,trunk块的大小必须为8的倍数。
(3)、dlmalloc用3种不同的的链表结构来组织不同大小的空闲内存块。小于256字节的块使用malloc_chunk结构,按照大小组织在一起。由于尺寸小于的块一共有256/8=32,所以一共使用了32个malloc_chunk结构的环形链表来组织小于256的块。大小大于256字节的块由结构malloc_tree_chunk组成链表管理,这些块根据大小组成二叉树。而更大的尺寸则由系统通过mmap的方式单独分配一块空间,并通过malloc_segment组成的链表进行管理。
(4)、当dlmalloc分配内存时,会通过查找这些链表来快速找到一块和要求的尺寸大小最匹配的空闲内存块(这样做事为了尽量避免内存碎片)。如果没有合适大小的块,则将一块大的分成两块,一块分配出去,另一块根据大小再加入对应的空闲链表中。
(5)、当dlmalloc释放内存时,会将相邻的空闲块合并成一个大块来减少内存碎片。如果空闲块过多,超过了dlmaloc内存的阀值,dlmalloc就开始向系统返回内存。
(6)、dlmalloc除了能管理进程的"堆"空间,还能提供私有堆管理,就是在堆外单独分配一块地址空间,由dlmalloc按照同样的方式进行管理。dlmalloc中用来管理进程的"堆"空间的函数,都带有"dl"前缀,如"dlmalloc","dlfree"等,而私有堆的管理函数则带有前缀"msspace_",如"msspace_malloc"
Bionic库的模块简介
Bionic目录下一共有5个库和一个linker程序,5个库分别是:
libc、libm、libdl、libstd++、libthread_db
(1)、Libc库
Libc是C语言最基础的库文件,它提供了所有系统的基本功能,这些功能主要是对系统调用的封装,是Libc是应用和Linux内核交流的桥梁,主要功能如下(上文有简述):
进程管理:包括进程的创建、调度策略和优先级的调整
线程管理:包括线程的创建和销毁,线程的同步/互斥等
内存管理:包括内存分配和释放等
时间管理:包括获取和保存系统时间、获取当前系统运行时长等
时区管理:包括时区的设置和调整等
定时器管理:提供系统的定时服务
文件系统管理:提供文件系统的挂载和移除功能
文件管理:包括文件和目录的创建增删改
网络套接字:创建和监听socket,发送和接受
DNS解析:帮助解析网络地址
信号:用于进程间通信
环境变量:设置和获取系统的环境变量
Android Log:提供和Android Log驱动进行交互的功能
Android 属性:管理一个共享区域来设置和读取Android的属性
标准输入/输出:提供格式化的输入/输出
字符串:提供字符串的移动、复制和比较等功能
宽字符:提供对宽字符的支持。
(2)、Libm库
Libm 是数学函数库,提供了常见的数学函数和浮点运算功能,但是Android浮点运算时通过软件实现的,运行速度慢,不建议频繁使用。
(3)、libdl库
libdl库原本是用于动态库的装载。很多函数实现都是空壳,应用进程使用的一些函数,实际上是在linker模块中实现。
(4)、Libm库
libstd++ 是标准的C++的功能库,但是,Android的实现是非常简单的,只是new,delete等少数几个操作符的实现。
(5)、libthread_db库
libthread_db 用来支持对多线程的中动态库的调试。
(6)、Linker模块
Linux系统上其实有两种并不完全相同的可执行文件
一种是静态链接的可执行程序。静态可执行程序包含了运行需要的所有函数,可以不依赖任何外部库来运行。另一种是动态链接的可执行程序。动态链接的可执行程序因为没有包含所需的库文件,因此相对于要小很多。
静态可执行程序用在一些特殊场合,例如系统初始化时,这时整个系统还没有准备好,动态链接的程序还无法使用。系统的启动程序Init就是一个静态链接的例子。在Android中,会给程序自动加上两个".o"文件,分别是"crtbegin_static.c"和"certtend_android.o",这两个".o"文件对应的源文件位于bionic/libc/arch-common/bionic目录下,文件分别是crtbegin.c和certtend.S。_start()函数就位于cerbegin.c中。
在动态链接时,execuve()函数会分析可执行文件的文件头来寻找链接器,Linux文件就是ld.so,而Android则是Linker。execuve()函数将会将Linker载入到可执行文件的空间,然后执行Linker的_start()函数。Linker完成动态库的装载和符号重定位后再去运行真正的可执行文件的代码。
代码示例
该示例只是为了展示 Bionic 库中一些常见函数的用法,实际应用中会更加复杂和多样化。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
// 使用 Bionic 中的内存分配函数 malloc 和 free
char *str = (char *)malloc(100);
strcpy(str, "Hello from Bionic example.");
printf("%s\n", str);
free(str);
// 使用 Bionic 中的字符串比较函数 strcmp
char str1[] = "Apple";
char str2[] = "Banana";
if (strcmp(str1, str2) < 0) {
printf("%s comes before %s.\n", str1, str2);
} else {
printf("%s comes before %s.\n", str2, str1);
}
return 0;
}
在实际的 Android 开发中 Bionic 已经被广泛应用。开发者们可以充分利用其强大的功能,快速构建出高质量的 Android 应用。同时,由于其开源性质,开发者社区可以对其进行进一步的改进和扩展,共同推动 Android 生态系统的发展。其作为谷歌为 Android 开发的标准库,为其开发者提供了强大的工具和支持。通过适当增加代码进行扩展,可以充分发挥其优势,为用户带来更加出色的 Android 应用与开发体验。
最新版本:1.0
v1.0.14于2019年7月发布。
官方主页:https://developer.android.com/
它是Android平台为了使用C/C++进行原生应用程序开发所有提供的POSIX标准C库;是Google为Android操作系统提供的BSD标准C库的衍生库;同时它也是专门为移动计算而精心设计的,针对移动设备上有限的CPU周期和可用内存进行了裁剪以提高工作效率。尽管其是C标准库,但是它不以任何方式与其它C库二进制兼容。也就是说Bionic和其它C库不兼容,无法进行交叉编译和相互引用,它是连接Android系统和Linux系统内核的纽带。其包含了系统中最基本的lib库,包括libc,libm,libdl,libstd++,libthread_db,以及Android特有的链接器linker。
Bionic提供了C标准库,类型定义,函数和少数Android特有的特性。主要功能可以概括如下:
内存管理
文件输入输出
字符串操作
数学函数
日期和时间
进程控制
信号处理
网络套接字
多线程
用户和组
系统配置
命名服务切换
GPL世界和非GPL世界的分界线在于一个叫做 Bionic Libc 的类库。其关键之处在于如果 Bionic Libc 受到内核 GPL 的“感染”,将会波及非 GPL 的用户空间的各个模块。谷歌使用Bionic库主要因为有以下三点考量:
1.谷歌没有使用Linux的GUN Libc,很大一部分原因是因为GNU Libc的授权方式是GPL授权协议有限制,因为一旦软件中使用了GPL的授权协议,该系统所有代码必须开源。
2.谷歌在BSD的C库上的基础上加入了一些Linux特性从而生成了Bionic。该名字的来源就是BSD和Linux的混合。而且不受限制的开源方式,所以在现代的商业公司中比较受欢迎。
3.另外就是因为性能的原因,因为Bionic的核心设计思想就是"简单",所以其中去掉了很多高级功能。这样Bionic库仅为200K左右,是GNU版本体积的一半,这意味着更高的效率和低内存的使用,同时配合经过优化的Java VM Dalvik才可以保证高的性能。
知乎的博睿数据对此有比较详细的叙述:
在 2008 年 Google IO大会上,一份著名的 PPT:“Android Anatomy And Physiology” 讲到 Android 使用 Bionic Libc 类库替换Linux常用的 Gnu glibc ,其中一个主要原因是 “We want to keep GPL out of user-”。(这其实有点难理解,毕竟 Gnu glibc 采用的是 LGPL 而非 GPL,并基于上文 GPL 第一点的讨论,使用系统调用的程序不再被视为 Linux 内核的衍生产品,并不需要遵循 GPL) 。Bionic Libc 充满着非议,Bionic Libc 拷贝内核头文件的行为,并在源码中声明的版权信息均遭到了 侵犯 Linux 内核 GPL 约束 ” 的质疑。
这是 Bionic 头文件的版权信息,许多人认为是非法的:“This header was automatically generated from a Linux kernel header of the same name, to make information necessary for userspace to call into the kernel available to libc. It contains only constants, structures, and macros generated from the original header, and thus, contains no copyrightable information.”
头文件由Linux内核的同名头文件自动生成,用来获取完成用户空间系统调用的必要的信息。它只包含原头文件中的常数、结构和宏定义,因此,不包含版权信息。不管如何,从目前的情况看,让 GPL 止步于内核空间的做法是成功的,并已经得到很大一部分内核开发者的认同。James Bottomley,Linux SCSI 子系统的维护者在 2011年 LinuxCon 大会日本站上谈到 Android 的商业成功与 GPL 恐惧的时候说:We should also design more “bright line” systems which make the question of GPL compliance clear. The kernel’s user-space ABI is one such system; developers know that user-space code is not considered to be derived from the kernel. Making the boundary easy to understand helps to make the GPL less scary.
在遵守 GPL 的问题上,我们必须澄清一些界线。内核的用户空间 ABI(应用二进制接口)就是一种 GPL 的作用边界,能让开发者意识到用户空间的代码,不被定性为内核的衍生产品,如果 GPL 的界线清晰而易懂,可以帮助大家消除对 GPL 的恐惧。
Android 的发展离不开硬件设备厂商的支持,硬件设备厂商最关注的是 Linux 驱动的 GPL 约束问题,公开驱动程序源代码将会泄漏设备的硬件规格和泄漏核心知识产权,这是硬件厂商 GPL 恐惧的缘由。Google 不遗余力的为硬件设备厂家排忧艰难,保驾护航。上文提到的 “Android Anatomy And Physiology”,文中清晰的讲到 Android 在用户空间与内核空间之间存在着硬件抽象层 HAL(Hardware Abstraction Layer),HAL 类库本质上一种用户空间的驱动,其中的主要用途之一:规避 GPL。
Bionic 具有诸多显著优势。首先它经过了严格的优化,以适应移动设备的资源限制和性能要求。在内存管理、线程调度等方面表现出色,能够确保 Android 应用程序在不同硬件平台上都能高效运行。这个标准库提供了丰富的功能,涵盖了字符串处理、数学运算、文件操作等多个方面。例如,它提供了高效的字符串拼接和查找函数,以及快速的数学计算函数。在文件操作方面,Bionic 支持多种文件系统,并提供了安全可靠的文件读写功能。需要注意的是,通常在 Android 开发中,会使用 Java 或 Kotlin 语言进行应用开发,较少直接使用 Bionic 库中的函数进行编程。但在 Android 的底层开发或使用 NDK(Native Development Kit)进行 C/C++ 开发时,可能会涉及到使用 Bionic 库的函数。
Bionic与Glibc
Bionic当前支持ARM、x86和MIPS执行集,理论上可以支持更多,但是需要做些工作,ARM相关的代码在目录arch-arm中,x86相关代码在arch-x86中,mips相关的代码在arch-mips中。Android使用Bionic而不使用Glibc的最主要原因:
1.有限的空间和存储
2.较低的CPU速度
3.不完全开源
Bionic的优势
1.去除头文件的相关内容,占用更小的存储
2.规避GPL,上文有述
3.占用更小的空间,Bionic 大约 200KB, Glibc 400KB,(去除臃肿的代码以及不必要的功能)
4.低速CPU优化,主要源于对pthread的优化,这也是一个缺点,因为他只专门为低时钟频率的 CPU设计
Bionic的限制和缺点
异常处理、STL 不支持
Pthreads
Cancellation 不支持
pthread_once() 不支持 初始化函数和初始化函数调用fork()的异常处理
pthread_atfork()函数 不支持
不支持区域和宽字符,程序员应该使用Unicode
用户账户相关功能,没有真正实现,这是目前只支持单用户的原因
Bionic的内存管理器:dlmalloc
dlmalloc是一个十分流行的内存分配器。dlmalloc位于bionic/libc/upstream-dlmalloc下,只有一个C文件malloc.c。其原理大致如下:
(1)、dlmalloc内部是以链表的形式将"堆"的空闲空间根据尺寸组织在一起。分配内存时通过这些链表能快速地找到合适大小的空闲内存。如果不能找到满足要求的空闲内存,dlmalloc会使用系统调用来扩大堆空间。
(2)、dlmalloc内存块被称为"trunk"。每块大小要求按地址对齐(默认8个字节),因此,trunk块的大小必须为8的倍数。
(3)、dlmalloc用3种不同的的链表结构来组织不同大小的空闲内存块。小于256字节的块使用malloc_chunk结构,按照大小组织在一起。由于尺寸小于的块一共有256/8=32,所以一共使用了32个malloc_chunk结构的环形链表来组织小于256的块。大小大于256字节的块由结构malloc_tree_chunk组成链表管理,这些块根据大小组成二叉树。而更大的尺寸则由系统通过mmap的方式单独分配一块空间,并通过malloc_segment组成的链表进行管理。
(4)、当dlmalloc分配内存时,会通过查找这些链表来快速找到一块和要求的尺寸大小最匹配的空闲内存块(这样做事为了尽量避免内存碎片)。如果没有合适大小的块,则将一块大的分成两块,一块分配出去,另一块根据大小再加入对应的空闲链表中。
(5)、当dlmalloc释放内存时,会将相邻的空闲块合并成一个大块来减少内存碎片。如果空闲块过多,超过了dlmaloc内存的阀值,dlmalloc就开始向系统返回内存。
(6)、dlmalloc除了能管理进程的"堆"空间,还能提供私有堆管理,就是在堆外单独分配一块地址空间,由dlmalloc按照同样的方式进行管理。dlmalloc中用来管理进程的"堆"空间的函数,都带有"dl"前缀,如"dlmalloc","dlfree"等,而私有堆的管理函数则带有前缀"msspace_",如"msspace_malloc"
Bionic库的模块简介
Bionic目录下一共有5个库和一个linker程序,5个库分别是:
libc、libm、libdl、libstd++、libthread_db
(1)、Libc库
Libc是C语言最基础的库文件,它提供了所有系统的基本功能,这些功能主要是对系统调用的封装,是Libc是应用和Linux内核交流的桥梁,主要功能如下(上文有简述):
进程管理:包括进程的创建、调度策略和优先级的调整
线程管理:包括线程的创建和销毁,线程的同步/互斥等
内存管理:包括内存分配和释放等
时间管理:包括获取和保存系统时间、获取当前系统运行时长等
时区管理:包括时区的设置和调整等
定时器管理:提供系统的定时服务
文件系统管理:提供文件系统的挂载和移除功能
文件管理:包括文件和目录的创建增删改
网络套接字:创建和监听socket,发送和接受
DNS解析:帮助解析网络地址
信号:用于进程间通信
环境变量:设置和获取系统的环境变量
Android Log:提供和Android Log驱动进行交互的功能
Android 属性:管理一个共享区域来设置和读取Android的属性
标准输入/输出:提供格式化的输入/输出
字符串:提供字符串的移动、复制和比较等功能
宽字符:提供对宽字符的支持。
(2)、Libm库
Libm 是数学函数库,提供了常见的数学函数和浮点运算功能,但是Android浮点运算时通过软件实现的,运行速度慢,不建议频繁使用。
(3)、libdl库
libdl库原本是用于动态库的装载。很多函数实现都是空壳,应用进程使用的一些函数,实际上是在linker模块中实现。
(4)、Libm库
libstd++ 是标准的C++的功能库,但是,Android的实现是非常简单的,只是new,delete等少数几个操作符的实现。
(5)、libthread_db库
libthread_db 用来支持对多线程的中动态库的调试。
(6)、Linker模块
Linux系统上其实有两种并不完全相同的可执行文件
一种是静态链接的可执行程序。静态可执行程序包含了运行需要的所有函数,可以不依赖任何外部库来运行。另一种是动态链接的可执行程序。动态链接的可执行程序因为没有包含所需的库文件,因此相对于要小很多。
静态可执行程序用在一些特殊场合,例如系统初始化时,这时整个系统还没有准备好,动态链接的程序还无法使用。系统的启动程序Init就是一个静态链接的例子。在Android中,会给程序自动加上两个".o"文件,分别是"crtbegin_static.c"和"certtend_android.o",这两个".o"文件对应的源文件位于bionic/libc/arch-common/bionic目录下,文件分别是crtbegin.c和certtend.S。_start()函数就位于cerbegin.c中。
在动态链接时,execuve()函数会分析可执行文件的文件头来寻找链接器,Linux文件就是ld.so,而Android则是Linker。execuve()函数将会将Linker载入到可执行文件的空间,然后执行Linker的_start()函数。Linker完成动态库的装载和符号重定位后再去运行真正的可执行文件的代码。
代码示例
该示例只是为了展示 Bionic 库中一些常见函数的用法,实际应用中会更加复杂和多样化。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
// 使用 Bionic 中的内存分配函数 malloc 和 free
char *str = (char *)malloc(100);
strcpy(str, "Hello from Bionic example.");
printf("%s\n", str);
free(str);
// 使用 Bionic 中的字符串比较函数 strcmp
char str1[] = "Apple";
char str2[] = "Banana";
if (strcmp(str1, str2) < 0) {
printf("%s comes before %s.\n", str1, str2);
} else {
printf("%s comes before %s.\n", str2, str1);
}
return 0;
}
在实际的 Android 开发中 Bionic 已经被广泛应用。开发者们可以充分利用其强大的功能,快速构建出高质量的 Android 应用。同时,由于其开源性质,开发者社区可以对其进行进一步的改进和扩展,共同推动 Android 生态系统的发展。其作为谷歌为 Android 开发的标准库,为其开发者提供了强大的工具和支持。通过适当增加代码进行扩展,可以充分发挥其优势,为用户带来更加出色的 Android 应用与开发体验。
最新版本:1.0
v1.0.14于2019年7月发布。
官方主页:https://developer.android.com/