快乐Linux —— 7. 主函数参数 & 系统调用和库函数 & 时间处理
参考:
https://www.cnblogs.com/tuhooo/p/7226567.html
https://blog.csdn.net/qq_37375427/article/details/80067272
0. 简述
从这一节开始,迈入编程部分。
1. 主函数的参数。
int main()
int main(void)
int main(int argc, char *argv[])
int main(int argc, char *argv[], char *envp[])
一般而言主函数有以上常见形式,其中
-
int argc
代表了 命令行参数总个数,包括可执行程序名。 -
char *argv[]
命令行参数数组,每个元素都是字符数组类型。
!!!:第一个存放的是运行程序的命令。最后一个存放的是NULL,即argv[argc] == NULL。
char *envp[]
存放的是环境变量的字符数组。
!!!:最后一个存放的是NULL,即envp[argc] == NULL。
https://blog.csdn.net/msdnwolaile/article/details/50610150
关于为什么主函数在调用时能够获得这些参数?
简单来说是因为在运行主函数前,操作系统会先做一些准备工作。
这篇博文讲详细讲解了上图这个过程:https://blog.csdn.net/sxh741/article/details/54970085
2. 系统调用和库函数
两者的区别
- 所有 C 函数库是相同的,而各个操作系统的系统调用是不同的。
- 函数库调用是调用函数库中的一个程序,而系统调用是调用系统内核的服务。
- 函数库调用是与用户程序相联系,而系统调用是操作系统的一个进入点
- 函数库调用是在用户地址空间执行,而系统调用是在内核地址空间执行
- 函数库调用的运行时间属于「用户」时间,而系统调用的运行时间属于「系统」时间
- 函数库调用属于过程调用,开销较小,而系统调用需要切换到内核上下文环境然后切换回来,开销较大
- 在C函数库libc中大约 300 个程序,在 UNIX 中大约有 90 个系统调用
- 函数库典型的 C 函数:system, fprintf, malloc,而典型的系统调用:chdir, fork, write, brk
后文我们会分别看看关于文件的系统调用IO 和 库函数IO。
出错处理
#include <errno.h> 这个头文件里面有全局变量 errno 对于 errno 应当知道两条规则:
- 如果没有出错,则其值不会被一个例程清除。因此,仅当函数的返回值指明出错时,才检验其值。
- 任一函数都不会将 errno 值设置为0,在< errno.h>中定义的所有常量都不为 0。
有两个函数可以帮助我们打印出错信息
#include <string.h>
char * strerror(int errnum);
#include <stdio.h>
void perror(const char *msg);
char * strerror(int errnum);
将errno 的值映射为字符串并返回。
void perror(const char *msg);
输出msg 后再输出errno 映射的字符串。
所映射的字符串就是在 < errno.h> 里对错误的描述。
时间处理
Unix 一直使用两种时间:
- 日历时间,基于1970年 1月 1日 00: 00: 00 以来所经历的秒数。 基本数据类型 time_t
- 进程时间(又称CPU 时间)进程所执行的时间。 基本数据类型 clock_t
- 时钟时间。 进程运行时间总量。相当于 用户CPU时间 + 系统CPU 时间。
- 用户CPU 时间。执行用户命令所耗费的时间。
- 系统CPU 时间。执行系统服务所耗费的时间。
日历时间
#include <time.h>
time_t time(time_t *ptr);
//若成功,返回时间值并将其保存在参数ptr 内。否则返回 -1
#include <sys/time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz);
//可以精确到微秒,返回值总是0
/*
struct timeval{
time_t tv_sec; // seconds
long tv_usec; // microseconds
}
*/
将秒数转化为直观的时间
#include <time.h>
struct tm *gmtime(time_t *ptr);
struct tm *localtime(time_t *ptr);
//都是根据time_t 返回struct tm 结构体指针。
//不过gmtime 是使用国际时间,而localtime 使用本地时区。
time_t mktime(struct tm *ptr);
//与上面相反,根据struct tm 返回 time_t
char *asctime(struct tm *ptr);
char *ctime(time_t *ptr);
//两个函数都根据ptr 所代表的时间类型 返回时间字符串。(以\n\0结尾)
进程时间
#include <sys/times.h> //注意这个头文件是sys/times.h 头文件是sys/time.h
clock_t times(struct tms *ptr);
// 若成功返回 clock_t 并填充ptr所指的struct tms ,失败返回-1
clock_t 类型准确来说是 CPU 的滴答数,它只能代表一个过程量,即只能用它的相对量计时。每秒CPU 的滴答数由 sysconf(_SC_CLK_TCK) 返回值决定。
#include <stdio.h>
#include <sys/times.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
struct tms start_s, end_s;
clock_t start, end;
void ttime_start(){
start = times(&start_s);
}
void ttime_end(const char *str){
end = times(&end_s);
printf("%s \n",str);
printf("run time : %.2f\n",(double)(end-start)/sysconf(_SC_CLK_TCK));
printf("user cpu time : %.2f\n",
(end_s.tms_utime - start_s.tms_utime)/(double)sysconf(_SC_CLK_TCK ));
printf("system cpu time : %.2f\n",
(end_s.tms_stime - start_s.tms_stime)/(double)sysconf(_SC_CLK_TCK ));
}
int main()
{
ttime_start();
for(int i=0;i<99999999;++i){
free(malloc(1024));
}
ttime_end("malloc - free");
ttime_start();
for(int i=0;i<99999999;++i){
time(NULL);
}
ttime_end("time");
ttime_start();
int sum=0;
for(int n=1000000000;n>0;--n)
{
sum += n - 50000;
}
ttime_end("for loop");
return 0;
}