说到宏,您可能会想到它常见的两个例子:
#define BUFFER_SIZE 1024
#define min(X, Y) ((X) < (Y) ? (X) : (Y))
更多关于宏的介绍,请查看GCC-OnlineDoc-Macros. 现在让我们来看下面这段代码,摘自Git的初始提交,没错Linus Torvalds写的那个Git. 当您克隆其仓库到本地后,您可以通过git checkout e83c5163316f89bfbde7d9ab23ca2e25604af290
命令签出其初始提交。
#ifdef BGIT_UNIX
#define STAT_TIME_SEC( st, st_xtim ) ( (st)->st_xtim ## e )
#define STAT_TIME_NSEC( st, st_xtim ) ( (st)->st_xtim.tv_nsec )
#elif defined BGIT_DARWIN
#define STAT_TIME_SEC( st, st_xtim ) ( (st)->st_xtim ## espec.tv_sec )
#define STAT_TIME_NSEC( st, st_xtim ) ( (st)->st_xtim ## espec.tv_nsec )
#elif defined BGIT_WINDOWS
#define STAT_TIME_SEC( st, st_xtim ) ( (st)->st_xtim ## e )
#define STAT_TIME_NSEC( st, st_xtim ) 0
#endif
上面那段代码,说到底是为了统一不同环境(Unix, Darwin, Windows)下对stat结构体中文件时间的访问(包括秒和纳秒)
实际上,在Unix系统下,您是通过(st)->st_ctim.tv_sec
访问文件的创建时间(秒),而在MacOSX系统下,您是通过(st)->st_ctimespec.tv_sec
访问文件的创建时间(秒)
在Linux下,您可以分别通过gcc -E show-diff.c -o show-diff-unix.i -D BGIT_UNIX
和gcc -E show-diff.c -o show-diff-darwin.i -D BGIT_DARWIN
命令生成经过预处理后的代码文件。
观察生成的show-diff-unix.i和show-diff-darwin.i文件和show-diff.c源文件,您可以发现原来代码文件中的下面这一段:
/* Check last modification time. */
if (ce->mtime.sec != (unsigned int)STAT_TIME_SEC( st, st_mtim ) ||
ce->mtime.nsec != (unsigned int)STAT_TIME_NSEC( st, st_mtim ))
changed |= MTIME_CHANGED;
在定义了BGIT_UNIX环境变量的情况下被展开成:
if (ce->mtime.sec != (unsigned int)( (st)->st_mtim.tv_sec ) ||
ce->mtime.nsec != (unsigned int)( (st)->st_mtim.tv_nsec ))
changed |= 0x0001;
在定义了BGIT_DARWIN环境变量的情况下被展开成:
if (ce->mtime.sec != (unsigned int)( (st)->st_mtimespec.tv_sec ) ||
ce->mtime.nsec != (unsigned int)( (st)->st_mtimespec.tv_nsec ))
changed |= 0x0001;
您可能发现这里有个问题,当BGIT_UNIX
环境变量存在时候,STAT_TIME_SEC( st, st_mtim )
应该会被展开成(st)->st_mtime
才对。那为什么我们上面经过预处理的代码中会变成(st)->st_mtim.tv_sec )
呢?
答案在stat结构体:
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_tst_mode;/* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev;/* device ID (if special file) */
off_t st_size;/* total size, in bytes */
blksize_t st_blksize; /* blocksize for filesystem I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
/* Since Linux 2.6, the kernel supports nanosecond
precision for the following timestamp fields.
For the details before Linux 2.6, see NOTES. */
struct timespec st_atim; /* time of last access */
struct timespec st_mtim; /* time of last modification */
struct timespec st_ctim; /* time o f last status change */
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
留意最后三行,原来STAT_TIME_SEC( st, st_mtim )
先被展开成(st)->st_mtime
,而后又被展开成(st)->st_mtim.tv_sec )
.
原文:https://www.cnblogs.com/lukeaxu/p/14723481.html