1.辅助工具
nm xxx.o/xxx.out/xxx.a/xxx.so:查看符号表,列出目标文件(.o)、可执行文件、静态库文件(.a)或动态库文件(.so)中的符号(函数名、变量及其地址等)
objdump -S xxx.o:显示二进制模块的反汇编信息
strip xxx.o/xxx.out/xxx.a/xxx.so:删除目标文件(.o)、可执行文件、静态库文件(.a)或动态库文件(.so)中的符号表和调试信息(减小文件大小,调试完后发布时用)
ldd xxx.out/xxx.so:查看可执行程序文件(.out)或动态库文件(.so)所依赖的动态库文件
2.错误号和错误信息
通过返回合法值域以外的值表示错误
int age(char const* name) {
…
return 1000;
}返回指针的函数:通过返回NULL指针表示错误
不需要通过返回值输出信息的函数:返回0表示成功,返回-1表示失败。
int delete(char const* filename) {
…
return 0;
…
return -1;
}
通过错误号和错误信息表示产生错误的具体原因
方法1:
#include <errno.h> 全局整数变量:errno标识最近一次系统调用的错误。方法2:
#include <string.h>
char* strerror(int errnum); // 根据错误号返回错误信息。方法3(常用):
#include <stdio.h>
void perror(const char* s);
参数s可传入提示信息,不提示传NULL。打印最近错误的错误信息。方法4:
printf函数的%m标记被替换为最近错误的错误信息#include <stdio.h> #include <string.h> #include <errno.h> int main(void) { FILE* fp = fopen("none", "r"); if (!fp) { printf("fopen: %d\n", errno);//方法1:需自己查找错误号的意思 printf("fopen: %s\n", strerror(errno));//方法2:直接打印出来 perror("fopen");//方法3:直接打印出来 printf("fopen: %m\n");//方法4:直接打印出来 return -1; } // ... fclose(fp); return 0; }
虽然所有的错误号都不是0,但是因为在函数执行成功的情况下错误号全局变量errno不会被清0,因此不能用errno是否为0作为函数成功失败的判断条件,是否出错还是应该根据函数的返回值来决定。
返回值 = 函数调用(…);
if (返回值表示函数调用失败) {
根据errno判断发生了什么错误
针对不同的错误提供不同的处理
}#include <stdio.h> #include <stdlib.h> #include <errno.h> int main(void) { FILE* fp = fopen("none", "r"); // if (errno) { if (!fp) { perror("fopen"); return -1; } int* pi = malloc(sizeof(int)); // if (errno) { //这里不用errno是因为前面文件打开失败时的错误号不会置零 if (!pi) { perror("malloc"); return -1; } // ... free(pi); fclose(fp); return 0; }
3.环境变量
每个进程都有一张独立的环境变量表,其中的每个条目都是一个形如“键=值”形式的环境变量。
终端命令行(查看bash下的环境变量):env所谓环境变量表就是一个以NULL指针结束的字符指针数组,其中的每个元素都是一个字符指针,指向一个以空字符结尾的字符串,该字符串就是形如”键=值”形式的环境变量。
全局变量:environ,是一个二级char型指针,需要自己在代码做外部声明。#include <stdio.h> #include <stdlib.h> //定义查看环境变量的函数,参数为全局变量environ void penv(char** env) { printf("---- 环境变量 ----\n"); while (env && *env)//当env的一级指针和二级指针不为空时,打印环境变量 printf("%s\n", *env++); printf("------------------\n"); } int main(int argc, char* argv[], char* envp[]) { //main的入口参数有三个,第三个其实为env环境变量表的首地址 extern char** environ; //外部声明拓展environ变量作用域 printf("%p %p\n", environ, envp);//environ,envp作用一样,都接收到环境变量表的首地址 penv(environ/*envp*/); return 0; }
一些环境变量的操作函数(在当前进程下的env,不一定是bash下的,当前的可通过命令行./env查看)
根据环境变量名获取其值 char* getenv(char const* name);
成功返回变量名匹配的变量值,失败返回NULL。
name - 环境变量名,即等号左边的部分添加或修改环境变量 int putenv(char* string);
成功返回0,失败返回-1。
string - 形如“键=值”形式的环境变量字符串 若其键已存在,则修改其中,若其键不存在,则添加新变量添加或修改环境变量 int setenv(const char* name, const char* value, int overwrite);
成功返回0,失败返回-1。
name - 环境变量名,即等号左边的部分
value - 环境变量值,即等号右边的部分
overwrite -当name参数所表示的环境变量名已存在,此参数取0则保持该变量的原值不变,若此参数取非0,则将该变量的值修改为value。(即0表示不覆盖,环境变量的键名存在时不做改变;非0时,发生覆盖)删除环境变量 int unsetenv(const char* name);
成功返回0,失败返回-1。
name - 环境变量名,即等号左边的部分清除(当前进程中)所有环境变量 int clearenv(void);
成功返回0,失败返回-1。#include <stdio.h> #include <stdlib.h> void penv(char** env) { printf("---- 环境变量 ----\n"); while (env && *env)//当env的一级指针和二级指针不为空时,打印环境变量 printf("%s\n", *env++); printf("------------------\n"); } int main(int argc, char* argv[], char* envp[]) { //获取环境变量中HOME这个键的值 printf("HOME=%s\n", getenv("HOME")); //添加或修改环境变量,若其键已存在,则修改其中,若其键不存在,则添加新变量 if (putenv("NAME=Helpsen") == -1) { perror("putenv"); return -1; } //第三个参数:0表示不覆盖,环境变量的键名存在时不做改变;非0时,发生覆盖,更改键值 if (setenv("NAME", "HelpsenChen", 1) == -1) { perror("setenv"); return -1; } //查看环境变量表,查看覆盖情况 penv(environ); //第三个参数:0表示不覆盖,环境变量的键名存在时不做改变 if (setenv("NAME", "ChenHelpsen", 0) == -1) { perror("setenv"); return -1; } //查看环境变量表,查看覆盖情况 penv(environ); //清除环境变量表中的NAME键和其值 if (unsetenv("NAME") == -1) { perror("unsetenv"); return -1; } //查看环境变量表,是否以清除NAME的键和其值 penv(environ); //清除(当前进程中)所有环境变量 if (clearenv() == -1) { perror("clearenv"); return -1; } //查看environ是否为空指针了 printf("%p\n", environ); //查看环境变量表内容是否已清空 penv(environ); return 0; } ```