Loading

快乐Linux —— 7. 主函数参数 & 系统调用和库函数 & 时间处理

参考:

https://www.cnblogs.com/tuhooo/p/7226567.html

https://blog.csdn.net/qq_37375427/article/details/80067272

https://blog.csdn.net/msdnwolaile/article/details/50610150

https://www.cnblogs.com/liwei0526vip/p/8998751.html

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 应当知道两条规则:

  1. 如果没有出错,则其值不会被一个例程清除。因此,仅当函数的返回值指明出错时,才检验其值。
  2. 任一函数都不会将 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 一直使用两种时间:

  1. 日历时间,基于1970年 1月 1日 00: 00: 00 以来所经历的秒数。 基本数据类型 time_t
  2. 进程时间(又称CPU 时间)进程所执行的时间。 基本数据类型 clock_t
    1. 时钟时间。 进程运行时间总量。相当于 用户CPU时间 + 系统CPU 时间。
    2. 用户CPU 时间。执行用户命令所耗费的时间。
    3. 系统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;
}
posted @ 2019-11-24 10:35  沉云  阅读(314)  评论(0编辑  收藏  举报