LINUX C语言 宏定义

LINUX C语言 宏定义,第1张

如果直接传整型数字进去默认应该是int吧

所以展开应该是

int _a = (2)

int _b = (3)

_a>_b?_a:_b

如果在使用宏的时候, a和b的类型是自己定义的类型 例如:

salary a

salary b

现在要调用宏来比较他俩的大小

salary n

n = max(a,b)<==>(salary _a = (a) salary _b = (b) _a>_b?_a:_b)

这样的求最大数的宏是目前最安全的写法

命令是查询当前登录的每个用户,它的输出包括用户名、终端类型、登录日期及远程主机,在Linux系统中输入who命令输出如下:

我们先man一下who,在帮助文档里可以看到,who命令是读取/var/run/utmp文件来得到以上信息的。

我们再man一下utmp,知道utmp这个文件,是二进制文件,里面保存的是结构体数组,这些数组是struct utmp结构体的。

struct utmp {

short ut_type

pid_t ut_pid

charut_line[UT_LINESIZE]

charut_id[4]

charut_user[UT_NAMESIZE]

charut_host[UT_HOSTSIZE]

struct {

int32_t tv_sec

int32_t tv_usec

} ut_tv

/***等等***/

}

要实现who只需要把utmp文件的所有结构体扫描过一遍,把需要的信息显示出来就可以了,我们需要的信息有ut_user、ut_line、ut_tv、ut_host。

老师给的初始代码:who1.c运行结果如下:

需要注意的是utmp中所保存的时间是以秒和微妙来计算的,所以我们需要把这个时间转换为我们能看懂的时间,利用命令man -k time | grep 3搜索C语言中和时间相关的函数

经过搜索发现了一个ctime()函数,似乎可以满足我们的需求,于是对代码中关于时间的printf进行修改:

printf("%s",ctime(&utbufp->ut_time))

编译运行发现出来的结果虽然已经转换成了我们能看懂的时间格式,但是很明显这个时间是错的:

搜索一下ut_time这个宏,发现它被定义为int32_t类型:

但是ctime()函数中要求参数的类型是time_t类型,所以重新定义一下类型,编译运行之后,发现时间已经改成了正确的,但是发现()中的内容被换行了,猜想ctime()函数的返回值可能自动在最后补了一个字符\n:

一开始想通过\r\b来实现“退行”,但实践后发现并不可取,最后考虑到直接修改字符串中最后一个字符为\0,让其字符串结束,使输出达到与系统who命令一样的效果,即在输出语句前添加如下代码:

cp[strlen(cp)-1] = '\0'

最后编译执行效果,发现解决了该问题:

虽然能看出基本上和who指令的执行结果一致,但是并非完全一样,主要在两点,第一是时间格式不一样,第二个是比who执行的结果多了几条,需要注意的是utmp中保存的用户,不仅仅是已经登陆的用户,还有系统的其他服务所需要的“用户”,所以在显出所有登陆用户的时候,应该过滤掉其他用户,只保留登陆用户。我们可以通过ut_type来区别,登陆用户的ut_type是USER_PROCESS。

先用if语句对执行结果进行过滤,效果如下:

接着解决时间格式问题,利用man命令收到了两个非常有用的函数:localtime()和strftime(),localtime()是把从1970-1-1零点零分到当前时间系统所偏移的秒数时间转换为本地时间,strftime()则是用来定义时间格式的,如:年-月-日,利用这两个函数对时间进行修改后,结果显示终于和系统中who命令一模一样:

最终完整的代码如下:

#include <stdio.h>

#include <stdlib.h>

#include <utmp.h>

#include <fcntl.h>

#include <unistd.h>

#include <time.h>

#define SHOWHOST

void show_time(long timeval){

char format_time[40]

struct tm *cp

cp = localtime(&timeval)

strftime(format_time,40,"%F %R",cp)

printf("%s",format_time)

}

int show_info( struct utmp *utbufp )

{

if(utbufp->ut_type == USER_PROCESS){

printf("%-8.8s", utbufp->ut_name)

printf(" ")

printf("%-8.8s", utbufp->ut_line)

printf(" ")

show_time(utbufp->ut_time)

printf(" ")

#ifdef SHOWHOST

printf("(%s)", utbufp->ut_host)

#endif

printf("\n")

}

return 0

}

int main()

{

struct utmp current_record

int utmpfd

int reclen = sizeof(current_record)

if ( (utmpfd = open(UTMP_FILE, O_RDONLY)) == -1 ){

perror( UTMP_FILE )

exit(1)

}

while ( read(utmpfd, &current_record, reclen) == reclen )

show_info(&current_record)

close(utmpfd)

return 0

}

宏是一种预处理指令,它提供了一种机制,可以用来替换源代码中的字符串。

1、条件编译:

C语言中,预处理过程读入源代码,检查包含预处理指令的语句和宏定义,并对源代码进行相应的转换,预处理过程还会删除程序中的注释和多余的空白符号。

预处理指令是以#开头的代码行,#必须是该行除了空白字符外的第一个字符。#后是指令关键字,在#和指令关键字之间允许存在若干空白字符。

使用宏进行条件编译的用法与使用宏防止多重引用类似。示例如下:

使用条件编译,方便程序员在调试程序的过程中,执行一些在程序发布后并不需要执行的指令。只要在需要调试的代码前加上_DEBUG的定义,就可以在调试程序的过程中输出调试信息。

这样方便查看程序在运行过程中有没有出现错误,定位错误出现的地方。而在程序发布之前,取消_DEBUG的定义就可以不再执行调试代码。

2、宏函数:

函数的调用是需要一定的时间和空间代价的。因为系统在调用函数时,需要保留"现场",即将程序要执行的指令的下一条指令的位置压入栈,然后转入调用函数去执行,调用完函数后再返回主调函数,恢复"现场",返回到栈里保存的的下一条指令的位置继续执行。

所以函数的调用需要额外的时间和空间代价。

而宏函数则不存在上述问题,宏函数在预编译时,同函数定义的代码来替换函数名,将函数代码段嵌入到当前程序,不会产生函数调用。

所以会省去普通函数保留现场恢复现场的时间,但因为要将定义的函数体嵌入到当前程序,所以不可避免的会占用额外的存储空间。

在频繁调用同一个宏的时候,该现象尤其明显。宏函数的示例定义如下:

#define MAX(a,b) ((a)<(b)?(b):(a))

宏函数的优点在于避免函数调用,提高程序效率。

同时需要注意的是inline标识符。inline也将函数定义为内联的。但是使用内联函数需要注意的是:函数体必须十分简单,不能含有循环、条件、选择等复杂结构,否则就不能作为内联函数了。

事实上,有时候即便你没有将函数指定为内联函数,编译器也会将一些简单的函数作为内联函数处理,而对于一些复杂的函数,即使声明为内联函数,编译器也不会理会的。

inline函数的瓶颈就在于此,使用inline标识符将函数声明为内联的,但这只是一种提示,到底编译器有没有优化还依赖于编译器的实现,而使用宏函数则完全由代码本身控制。

但在使用宏函数的时候,需要明确的是宏函数只是简单的替换,需要注意括号的使用。

扩展资料:

宏的更多规则特性:

(1)宏名一般用大写。

(2)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。例如:数组大小常用宏定义。

(3)预处理是在编译之前的处理,而编译工作的任务之一就是语法检查,预处理不做语法检查。

(4)宏定义末尾不加分号。

(5)宏定义写在函数的花括号外边,作用域为其后的程序,通常在文件的最开头。

(6)可以用#undef命令终止宏定义的作用域。

(7)宏定义不可以嵌套。

(8)字符串" "中永远不包含宏。

(9)宏定义不分配内存,变量定义分配内存。

(10)宏定义不存在类型问题,它的参数也是无类型的。

参考资料:

百度百科--宏定义


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/8213357.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-14
下一篇 2023-04-14

发表评论

登录后才能评论

评论列表(0条)

保存