Bionic是c和c++进行原生应用开发所提供的posix标准c库
1回顾标准库
Java平台的标准库是javaclasslibrary(JCL)
C语言的标准库为libc
2gnuc(glibc)embeddedlinuxc(uclibc)和bionic
Bionic提供以下功能:
内存管理
文件输入输出
字符串操作
数学
日期与时间
进程控制
信号处理
网络套接字
多线程
用户和组
系统配置
命名服务切换
AndroidNDK提供了缺失功能的完整列表,可以从头文件中获得这些信息
ANDROID_NDK_HOME/platforms/android-<api-level>/arch-<architecture>/usr/include
3内存管理
三种内存分配方式
静态分配:静态或全局变量
自动分配:函数参数和局部变量
动态分配:内存的大小和范围的分配取决于运行时因素
C语言的动态内存管理---------------------------------------------------------------
动态分配内存:
Void*malloc(size_tsize);//是以字节为单位来分配内存的
释放动态内存:
Void*free(void*memory);//通过之前指向动态内存的指针来释放内存
改变动态内存分配
Void*fealloc(void*memory,size_tsize);//重新分配内存
C++的动态内存管理-----------------------------------------------------------------
动态分配内存:
示例代码如下:
//单个元素的动态内存分配
Int*myInt=newint;
If(NULL==myInt){
//不能分配足够的内存
}else{
//使用分配的内存
*myInt=0;
}
//多个元素的动态内存分配
Int*myIntArray=newint[16];
Int*myIntArray=newint;
If(NULL==myInt){
//不能分配足够的内存
}else{
//使用分配的内存
myIntArray[8]=8;
}
释放动态内存:
//释放单个元素的动态内存
DeletemyInt;
myInt=0;
//释放多个元素的动态内存
Delete[]myIntArray;
myIntArray=0;
改变动态内存
使用适当的标准模板库(standardtemplatelibrarySTL)
4标准I/O
可以通过c库提供的satndardfileI/o(stdio)函数与文件系统进行交互
C库提供了两种文件i/o:
低级I/O:原始的i/o函数
流I/o:可缓冲的I/O函数,适合处理数据流
标准流#include<stdio.h>
Stdin:标准输入
Stdout:标准输出
Stderr:标准错误
打开流----------------------------------------------------------------------------
FILE*fopen(constchar*filename,//文件名
constchar*opentype);//控制文件打开方式
R只读
W只写
A以符加方式打开文件,不存在则新建
R+在读写模式下打开文件
W+在读写模式下打开文件,载断后文件长度为0
A+打开文件进行读取和符加
示例代码如下:
#include<stdio.h>
FILE*stream=fopen("/data/data/com.example.hellojni/test.txt","w");
if(NULL==stream){
MY_LOG_VERBOSE("cannotopen!");
}else{
//使用流
//关闭流
}
写入流-----------------------------------------------------------------------------------------------
//向流中写入数据块
size_tfwrite(constvoid*data,size_tsize,size_tcount,FILE*stream);
示例代码如下:
//使用fwrite向流中写入数据块
chardata[]={'h','e','l','l','o','\n'};
size_tcount=sizeof(data); //数据块长度
//向流中写入数据
if(count!=fwrite(data,sizeof(char),count,stream)){
MY_LOG_VERBOSE("fwriteerror!");
}else{
MY_LOG_VERBOSE("fwritesuccess!");
}
向流中写入字符序列
Intfputs(constchar*data,FILE*stream);
//向流中写入字符串序列
if(EOF==fput("hello\n",stream)){
MY_LOG_VERBOSE("fputerror!");
}else{
MY_LOG_VERBOSE("fputsuccess!");
}
向流中写入单个字符
Intfputc(intc,FILE*stream);
//向流中写入单个字符
charc='c';
if(c!=fputc(c,stream)){
MY_LOG_VERBOSE("fputcerror!");
}else{
MY_LOG_VERBOSE("fputcsuccess!");
}
//向流中写入有格式的字符串
Intfprintf(FILE*stream,constchar*format,...);
//向流中写入有格式的数据
if(0>fprintf(stream,"the%sis%d","number",2)){
MY_LOG_VERBOSE("fprintferror!");
}else{
MY_LOG_VERBOSE("fprintfsuccess!");
}
刷新缓冲区
Intfflush(FILE*stream);
流的读取--------------------------------------------------------------------------------------
从流中读取数据块
Size_tfread(void*data,size_tsize,size_tcount,FILE*stream);
//从流中读取四个字符的块数据
charbuffer[5];
size_ttmpSize=4;
if(tmpSize!=fread(buffer,sizeof(char),tmpSize,stream)){
MY_LOG_VERBOSE("freaderror!");
}else{
//以空结尾
buffer[4]=NULL;
//输出缓冲区到日志文件
MY_LOG_INFO("read:%s",buffer);
}
从流中读取字符序列
Char*fgets(char*buffer,intcount,FILE*stream);
//从流中读取字符串序列
charsBuffer[1024];
if(NULL==fgets(buffer,1024,stream)){
MY_LOG_VERBOSE("fgetserror!");
}else{
MY_LOG_INFO("fgetsread:%s",buffer);
}
从流中读取单个字符
Intfgetc(FILE*stream);
//从流中读取单个字符
unsignedcharch;
intresult;
result=fgetc(stream);
if(EOF==result){
MY_LOG_VERBOSE("fgetcerror!");
}else{
ch=(unsignedchar)result;
MY_LOG_INFO("fgetcread:%s",ch);
}
从流中读取格式数据
Intfscanf(FILE*stream,constchar*format,...);
//从流中读取格式字符串
chars[5];
inti;
if(2!=fscanf(stream,"the%sis%d",s,&i)){
MY_LOG_VERBOSE("fscanferror!");
}
检查文件结尾
Intfeof(FILE*stream);
//检查文件结尾
charcheckBuffer[1024];
while(0==feof(stream)){
fgets(buffer,1024,stream);
MY_LOG_INFO("fgetsread:%s",checkBuffer);
}
搜索位置------------------------------------------------------------
Intfseek(FILE*stream,//流指针
longoffset,//相对偏移量
intwhence);//位置参数
位置参数类型:
SEEK_SET:偏移量相对于流的开头
SEEK_CUR:偏移量相对于当前位置
SEEK_END:偏移量相对于流结尾
示例代码如下:
fputs("abcd",stream);
//倒回四个流字节
fseek(stream,-4,stream);
//用efgh重写abcd
fputs("efgh",stream);
错误检查----------------------------------------------------------------------------------
Intferror(FILE*stream);
//检查错误
if(0!=ferror(stream)){
//前一次请求中产生错误
}
关闭流--------------------------------------------------------------------------------------
Intfclose(FILE*stream);
//关闭流
if(0!=fclose(stream)){
MY_LOG_VERBOSE("fcloseerror!");
}
5与进程交互
执行shell命令(可以用system向shell传递命令)
#include<stdlib.h>
//用系统函数执行shell命令
intsysResult;
//在应用程序中新建目录
sysResult=system("mkdir/data/data/com.example.hellojni/temp");
if(-1==sysResult||127==sysResult){
MY_LOG_VERBOSE("shelloptionfailed!");
}
与子进程通信
FILE*popen(constchar*command,constchar*type);
//用ls打开一个通道并打印输出
FILE*tmpStream;
tmpStream=popen("ls","r");
if(NULL==stream){
MY_LOG_ERROR("unabletoexecutethecommand!");
}else{
charbuffer[1024];
intstatus;
//从命令行读取每一行
while(NULL!=fgets(buffer,1024,stream)){
MY_LOG_INFO("read:%s",buffer);
}
//关闭通道并获取其状态
status=pclose(stream);
MY_LOG_INFO("processexitedwithstatus%d",status);
}
6系统配置
Android的系统属性是以键值对的方式保存,bionic提供了一组函数来查询
需要包含的头文件
#include<sys/system_properties.h>
属性名最大值PROP_NAME_MAX
属性值最大值PROP_VALUE_MAX
通过名称获取系统属性值
Int__system_property_get(constchar*name,char*value);
//通过名称获取系统属性值
charparamValue[PROP_VALUE_MAX];
if(0==__system_property_get("ro.product.model",paramValue)){
MY_LOG_INFO("systempropertiescannotfindoritisnull!");
}else{
MY_LOG_INFO("productmodel:%s",paramValue);
}
通过名称获取系统属性值
Constprop_info*__system_property_find(constchar*name);
//通过名移获取系统属性
constprop_info*property;
property=__system_property_find("ro.product.model");
if(NULL==property){
MY_LOG_INFO("systempropertycannotfind!");
}else{
charname[PROP_NAME_MAX];
charvalue[PROP_VALUE_MAX];
//取得系统属性名称和值
if(0==__system_property_read(property,name,value)){
MY_LOG_INFO("%sisempty",name);
}else{
MY_LOG_INFO("%sis%s",name,value);
}
}
用户和组
需要头文件:
#include<unistd.h>
获取应用程序用户组
//使用getuid获得应用程序的用户id
uid_tuid;
uid=getuid();
MY_LOG_INFO("applicationuseridis%u",uid);
//使用getgid获得应用程序组id
gid_tgid;
gid=getgid();
MY_LOG_INFO("applicationgroupidis%u",gid);
获取应用程序用户名
//获取应用程序用户名
char*username;
username=getlogin();
MY_LOG_INFO("Applicationusernameis%s",username);
8进程间通信
Bionic暂不支持进程间通信