天天看点

clock_t实际类型的查找流程

把握clock_t 在系统中实际是什么类型,有助于编程 人员更好的使用该类型的变量,最直接的好处就是可以防止变量溢出,在溢出时能够准确判断可能存在问题的代码。现就将clock_t 的查找过程做简单记录。

1)

首先使用clock_t  类型变量需要包含<time.h>头文件,因此到该头文件中查找,而<time.h>位于哪里,使用locate命令进行查找。为什么使用locate命令可以参考这篇blog:http://blog.csdn.net/ysdaniel/article/details/7043298

通过locate命令查找后可以发现仅<time.h>在不同文件夹下就有多个,因此哪一个<time.h>是我们要查找的,这涉及头文件的查找顺序,可参考这篇blog:http://blog.csdn.net/chosen0ne/article/details/7210946

根据以上blog中的内容,在编译时未使用-I选项,C_INCLUDE_PATH与CPLUS_INCLUDE_PATH路径为空,因此<time.h>位于/usr/include中。终于确定了time.h 的位置。

2)

在<time.h>中直接查找,clock_t,可以找到如下定义

#if !defined __clock_t_defined && (defined _TIME_H || defined __need_clock_t)
# define __clock_t_defined	1

# include <bits/types.h>

__BEGIN_NAMESPACE_STD
/* Returned by `clock'.  */
typedef __clock_t clock_t;
__END_NAMESPACE_STD
#if defined __USE_XOPEN || defined __USE_POSIX
__USING_NAMESPACE_STD(clock_t)
#endif
           

在文件中无法找到__clock_t 的类型定义,不过发现包含<bits/types.h>。

3)

因此采用相同的方法,发现bits文件夹位于/usr/include/x86_64-linux-gnu/下,<type.h>中相关内容如下:

#include <bits/typesizes.h>
# define __STD_TYPE		typedef
__STD_TYPE __CLOCK_T_TYPE __clock_t;	/* Type of CPU usage counts.  */
           

依然无法进一步找到__CLOCK_T_TYPE的类型,同时发现包含<bits/typesizes.h>。

4)

在<typesizes.h>中查找__CLOCK_T_TYPE的相关内容如下:

/* See <bits/types.h> for the meaning of these macros.  This file exists so
   that <bits/types.h> need not vary across different GNU platforms.  */
#define __CLOCK_T_TYPE		__SYSCALL_SLONG_TYPE
           

再次查找__SYSCALL_SLONG_TYPE的内容,可找到如下内容

#if defined __x86_64__ && defined __ILP32__
# define __SYSCALL_SLONG_TYPE	__SQUAD_TYPE
# define __SYSCALL_ULONG_TYPE	__UQUAD_TYPE
#else
# define __SYSCALL_SLONG_TYPE	__SLONGWORD_TYPE
# define __SYSCALL_ULONG_TYPE	__ULONGWORD_TYPE
#endif
           

由于我的机器是64位,因此__SYSCALL_SLONG_TYPE类型为__SQUAD_TYPE,到此查找过程实际已进入死路,因为<typesizes.h>不再包含其他头文件,不过根据注释的内容,相同的宏定义在<types.h> 中,因此回到<types.h>。

5)

在<types.h>中直接查找__SQUAD_TYPE,可得相关内容如下:

#define	__S16_TYPE		short int
#define __U16_TYPE		unsigned short int
#define	__S32_TYPE		int
#define __U32_TYPE		unsigned int
#define __SLONGWORD_TYPE	long int
#define __ULONGWORD_TYPE	unsigned long int
#if __WORDSIZE == 32
# define __SQUAD_TYPE		__quad_t
# define __UQUAD_TYPE		__u_quad_t
# define __SWORD_TYPE		int
# define __UWORD_TYPE		unsigned int
# define __SLONG32_TYPE		long int
# define __ULONG32_TYPE		unsigned long int
# define __S64_TYPE		__quad_t
# define __U64_TYPE		__u_quad_t
/* We want __extension__ before typedef's that use nonstandard base types
   such as `long long' in C89 mode.  */
# define __STD_TYPE		__extension__ typedef
#elif __WORDSIZE == 64
# define __SQUAD_TYPE		long int
# define __UQUAD_TYPE		unsigned long int
# define __SWORD_TYPE		long int
# define __UWORD_TYPE		unsigned long int
# define __SLONG32_TYPE		int
# define __ULONG32_TYPE		unsigned int
# define __S64_TYPE		long int
# define __U64_TYPE		unsigned long int
/* No need to mark the typedef with __extension__.   */
# define __STD_TYPE		typedef
#else
# error
#endif
#include <bits/typesizes.h>	/* Defines __*_T_TYPE macros.  */
           

好了结果出来了,__SQUAD_TYPE类型为long int,即clock_t经过多重宏定义会被转换为long int。在编译时被包含的头文件会在包含文件中展开,__SYSCALL_SLONG_TYPE会被替换为long int,之后回溯的内容以此类推。

恩,恭喜你看到了这里。其实要知道clock_t 类型远不用这么麻烦,可以在编译时使用-E选项,-E选项的作用主要是对#include文件进行展开,并将#define的内容进行替换。

写一个简答的测试程序,#include<stdio.h>都不要了,只要#include<time.h>,测试程序如下:

#include <time.h>

int main()
{
	clock_t argu;
	return 0;
}
           

运行以下命令:

gcc -E -o test_clock_t.i test_clock_t.c 
           

相关内容如下:

typedef long int __clock_t;
typedef __clock_t clock_t;

int main()
{
 clock_t argu;
}
           

通过实验也可以发现,预编译过程对typedef不起作用。

继续阅读