错误处理
一般我们通过返回值的非法或合法表示错误,对于指针,NULL或0xffffffff表示错误。
当然还有一个全局变量errno用来表示错误编号。
char *strerror(int errnum); // 通过错误码来获取错误信息
void perror(const char *s); // 输出上一个操作的错误原因
#include <stdio.h>
#include <string.h>
#include <errno.h>
extern int errno;
int main()
{
FILE* frp = fopen("dwqjakl","r");
if(NULL == frp)
{
printf("%d\n",errno);
printf("%s\n",strerror(errno));
perror("fopen");
return -1;
}
}
输出结果为:
2
No such file or directory
fopen: No such file or directory
环境变量
操作会为每个程序分配一张环境变量表,程序对这张进行添加删除修改,是不会影响操作系统。
获取环境变量表的方式
1、声明一个二级指针 extern char** environ;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern char** environ;
void show_env(void)
{
printf("------------环境变量表------------\n");
for(int i=0; environ[i]; i++)
{
printf("%s\n",environ[i]);
}
}
int main()
{
show_env();
}
2、通过main函数参数获取
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char** argv,char** environ)
{
printf("------------环境变量表------------\n");
for(int i=0; environ[i]; i++)
{
printf("%s\n",environ[i]);
}
}
操作环境变量表
char *getenv(const char *name);
功能:获取环境变量的值
name:要获取的环境变量名
返回值:获取取的环境变量值的字符串首地址,找不返回值为NULL。
int putenv(char *string);
功能:向环境变量表中添加环境
string:name=value
返回值:成功返回0,失败返回非0。
int setenv(const char *name, const char *value, int overwrite);
功能:向环境变量表中添加环境变量
name:环境变量名
value:环境变量值
overwrite:如果环境已经存在,它决定了是否覆盖。
0 不覆盖
1 覆盖
int unsetenv(const char *name);
功能:从环境变量表中删除环境变量
name:要删除的环境变量名
int clearenv(void);
功能:清空环境变量表
将PATH给PATH追加一个"."路径
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char buf[255] = {};
printf("%s\n",getenv("PATH"));
strcpy(buf,getenv("PATH"));
strcat(buf,":.");
setenv("PATH",buf,1);
printf("%s\n",getenv("PATH"));
}
内存管理
STL中使用的是智能指针,类似与java的垃圾回收系统,可以实现自动分配自动释放。
C++中则使用new/delete关键字来申请内存。
C中通过malloc/free函数来申请内存。
POSIX则用过brk/sbrk,这是标准操作系统提供的接口。
Linux mmap/munmap 内存的映射和取消映射
内核 kmalloc/kfree
驱动 get_set_page
通过strace命令可以看到程序的系统内存调用。
#include <stdlib.h>
int main()
{
int *p = malloc(sizeof(int));
free(p);
}
一个简单的申请指针的代码,通过strace来查看他的内存调用。
strace ./a.out
execve("./a.out", ["./a.out"], [/* 64 vars */]) = 0
brk(0) = 0x20d9000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0a70a15000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=166042, ...}) = 0
mmap(NULL, 166042, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f0a709ec000
close(3) = 0
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0 \34\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2107816, ...}) = 0
mmap(NULL, 3932736, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f0a70434000
mprotect(0x7f0a705ea000, 2097152, PROT_NONE) = 0
mmap(0x7f0a707ea000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b6000) = 0x7f0a707ea000
mmap(0x7f0a707f0000, 16960, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f0a707f0000
close(3) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0a709eb000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0a709e9000
arch_prctl(ARCH_SET_FS, 0x7f0a709e9740) = 0
mprotect(0x7f0a707ea000, 16384, PROT_READ) = 0
mprotect(0x600000, 4096, PROT_READ) = 0
mprotect(0x7f0a70a16000, 4096, PROT_READ) = 0
munmap(0x7f0a709ec000, 166042) = 0
brk(0) = 0x20d9000
brk(0x20fa000) = 0x20fa000
brk(0) = 0x20fa000
exit_group(0) = ?
+++ exited with 0 +++
可以看到malloc接口,最后是通过brk接口来申请到内存的。