Bionic是c 和c++进行原生应用开发所提供的posix标准c库
1 回顾标准库
Java 平台的标准库是java class library(JCL)
C语言的标准库为libc
2 gnu c(glibc) embedded linux c(uclibc) 和bionic
Bionic提供以下功能:
内存管理
文件输入输出
字符串操作
数学
日期与时间
进程控制
信号处理
网络套接字
多线程
用户和组
系统配置
命名服务切换
AndroidNDK提供了缺失功能的完整列表,可以从头文件中获得这些信息
ANDROID_NDK_HOME/platforms/android-<api-level>/arch-<architecture>/usr/include
3 内存管理
三种内存分配方式
静态分配: 静态或全局变量
自动分配: 函数参数和局部变量
动态分配: 内存的大小和范围的分配取决于运行时因素
C语言的动态内存管理---------------------------------------------------------------
动态分配内存:
Void* malloc(size_t size); //是以字节为单位来分配内存的
释放动态内存:
Void* free(void* memory);//通过之前指向动态内存的指针来释放内存
改变动态内存分配
Void * fealloc(void* memory,size_t size);//重新分配内存
C++ 的动态内存管理 -----------------------------------------------------------------
动态分配内存:
示例代码如下:
//单个元素的动态内存分配
Int* myInt=new int;
If(NULL==myInt){
//不能分配足够的内存
}else{
//使用分配的内存
*myInt=0;
}
//多个元素的动态内存分配
Int* myIntArray=new int[16];
Int* myIntArray=new int;
If(NULL==myInt){
//不能分配足够的内存
}else{
//使用分配的内存
myIntArray[8]=8;
}
释放动态内存:
//释放单个元素的动态内存
Delete myInt;
myInt=0;
//释放多个元素的动态内存
Delete[] myIntArray;
myIntArray=0;
改变动态内存
使用适当的标准模板库(standard template library STL)
4标准I/O
可以通过c库提供的satndard file I/o(stdio)函数与文件系统进行交互
C 库提供了两种文件i/o:
低级I/O: 原始的i/o函数
流I/o: 可缓冲的I/O函数, 适合处理数据流
标准流 #include <stdio.h>
Stdin: 标准输入
Stdout: 标准输出
Stderr: 标准错误
打开流----------------------------------------------------------------------------
FILE* fopen(const char* filename,//文件名
const char* 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("can not open!");
}else{
//使用流
//关闭流
}
写入流-----------------------------------------------------------------------------------------------
//向流中写入数据块
size_t fwrite(const void* data,size_t size,size_t count,FILE* stream);
示例代码如下:
//使用fwrite向流中写入数据块
char data[] = { 'h', 'e', 'l', 'l', 'o', '\n' };
size_t count = sizeof(data); //数据块长度
//向流中写入数据
if (count != fwrite(data, sizeof(char), count, stream)) {
MY_LOG_VERBOSE("fwrite error!");
} else {
MY_LOG_VERBOSE("fwrite success!");
}
向流中写入字符序列
Int fputs(const char* data,FILE* stream);
//向流中写入字符串序列
if (EOF == fput("hello\n", stream)) {
MY_LOG_VERBOSE("fput error!");
} else {
MY_LOG_VERBOSE("fput success!");
}
向流中写入单个字符
Int fputc(int c,FILE* stream);
//向流中写入单个字符
char c = 'c';
if (c != fputc(c, stream)) {
MY_LOG_VERBOSE("fputc error!");
} else {
MY_LOG_VERBOSE("fputc success!");
}
//向流中写入有格式的字符串
Int fprintf(FILE* stream,const char* format,...);
//向流中写入有格式的数据
if (0 > fprintf(stream, "the %s is %d", "number", 2)) {
MY_LOG_VERBOSE("fprintf error!");
} else {
MY_LOG_VERBOSE("fprintf success!");
}
刷新缓冲区
Int fflush(FILE* stream);
流的读取--------------------------------------------------------------------------------------
从流中读取数据块
Size_t fread(void* data,size_t size,size_t count,FILE* stream);
//从流中读取四个字符的块数据
char buffer[5];
size_t tmpSize = 4;
if (tmpSize != fread(buffer, sizeof(char), tmpSize, stream)) {
MY_LOG_VERBOSE("fread error!");
} else {
//以空结尾
buffer[4] = NULL;
//输出缓冲区到日志文件
MY_LOG_INFO("read: %s", buffer);
}
从流中读取字符序列
Char* fgets(char* buffer,int count,FILE* stream);
//从流中读取字符串序列
char sBuffer[1024];
if (NULL == fgets(buffer, 1024, stream)) {
MY_LOG_VERBOSE("fgets error!");
} else {
MY_LOG_INFO("fgets read: %s", buffer);
}
从流中读取单个字符
Int fgetc(FILE* stream);
//从流中读取单个字符
unsigned char ch;
int result;
result = fgetc(stream);
if (EOF == result) {
MY_LOG_VERBOSE("fgetc error!");
} else {
ch = (unsigned char) result;
MY_LOG_INFO("fgetc read: %s", ch);
}
从流中读取格式数据
Int fscanf(FILE* stream,const char* format,...);
//从流中读取格式字符串
char s[5];
int i;
if (2 != fscanf(stream, "the %s is %d", s, &i)) {
MY_LOG_VERBOSE("fscanf error!");
}
检查文件结尾
Int feof(FILE* stream);
//检查文件结尾
char checkBuffer[1024];
while (0 == feof(stream)) {
fgets(buffer, 1024, stream);
MY_LOG_INFO("fgets read: %s", checkBuffer);
}
搜索位置------------------------------------------------------------
Int fseek(FILE* stream,//流指针
long offset,//相对偏移量
int whence);//位置参数
位置参数类型:
SEEK_SET:偏移量相对于流的开头
SEEK_CUR:偏移量相对于当前位置
SEEK_END:偏移量相对于流结尾
示例代码如下:
fputs("abcd", stream);
//倒回四个流字节
fseek(stream, -4, stream);
//用efgh重写abcd
fputs("efgh", stream);
错误检查----------------------------------------------------------------------------------
Int ferror(FILE* stream);
//检查错误
if(0!=ferror(stream)){
//前一次请求中产生错误
}
关闭流--------------------------------------------------------------------------------------
Int fclose(FILE* stream);
//关闭流
if (0 != fclose(stream)) {
MY_LOG_VERBOSE("fclose error!");
}
5 与进程交互
执行shell命令 (可以用system向shell传递命令)
#include <stdlib.h>
//用系统函数执行shell命令
int sysResult;
//在应用程序中新建目录
sysResult=system("mkdir /data/data/com.example.hellojni/temp");
if(-1==sysResult || 127==sysResult){
MY_LOG_VERBOSE("shell option failed!");
}
与子进程通信
FILE *popen(const char* command,const char* type);
//用ls打开一个通道并打印输出
FILE* tmpStream;
tmpStream = popen("ls", "r");
if (NULL == stream) {
MY_LOG_ERROR("unable to execute the command!");
} else {
char buffer[1024];
int status;
//从命令行读取每一行
while (NULL != fgets(buffer, 1024, stream)) {
MY_LOG_INFO("read: %s", buffer);
}
//关闭通道并获取其状态
status = pclose(stream);
MY_LOG_INFO("process exited with status %d", status);
}
6 系统配置
Android 的系统属性是以键值对的方式保存,bionic提供了一组函数来查询
需要包含的头文件
#include <sys/system_properties.h>
属性名最大值 PROP_NAME_MAX
属性值最大值 PROP_VALUE_MAX
通过名称获取系统属性值
Int __system_property_get(const char* name,char* value);
//通过名称获取系统属性值
char paramValue[PROP_VALUE_MAX];
if (0 == __system_property_get("ro.product.model", paramValue)) {
MY_LOG_INFO("system properties can not find or it is null!");
} else {
MY_LOG_INFO("product model: %s", paramValue);
}
通过名称获取系统属性值
Const prop_info* __system_property_find(const char* name);
//通过名移获取系统属性
const prop_info* property;
property = __system_property_find("ro.product.model");
if (NULL == property) {
MY_LOG_INFO("system property can not find!");
} else {
char name[PROP_NAME_MAX];
char value[PROP_VALUE_MAX];
//取得系统属性名称和值
if (0 == __system_property_read(property, name, value)) {
MY_LOG_INFO("%s is empty", name);
} else {
MY_LOG_INFO("%s is %s", name,value);
}
}
用户和组
需要头文件:
#include <unistd.h>
获取应用程序用户组
//使用getuid获得应用程序的用户id
uid_t uid;
uid = getuid();
MY_LOG_INFO("application user id is %u", uid);
//使用getgid获得应用程序组id
gid_t gid;
gid = getgid();
MY_LOG_INFO("application group id is %u", gid);
获取应用程序用户名
//获取应用程序用户名
char* username;
username = getlogin();
MY_LOG_INFO("Application user name is %s", username);
8 进程间通信
Bionic 暂不支持进程间通信