@yiltoncent
2015-04-16T05:47:00.000000Z
字数 5010
阅读 7318
C语言基础
在C库里面经常可以看到各种奇怪的宏,不知道是什么意思,但是C标准库已经存在了几十年,里面的东西都是成熟的,因此非常值得深入挖掘学习。
如stdlib.h里面:
/* Return the value of envariable NAME, or NULL if it doesn't exist. */extern char *getenv (__const char *__name) __THROW __nonnull ((1)) __wur;
这里面有__THROW,__nonull以及__wur三个不常见的宏。这都是什么意思呢?
这篇文章解释了__THROW到底是干什么的。
在LINUX目录/usr/include/sys/cdefs.h中就有关于__THROW的定义:
#ifdef __GNUC__/* GCC can always grok prototypes. For C++ programs we add throw()to help it optimize the function calls. But this works only withgcc 2.8.x and egcs. For gcc 3.2 and up we even mark C functionsas non-throwing using a function attribute since programs can usethe -fexceptions options for C code as well. */# if !defined __cplusplus && __GNUC_PREREQ (3, 3)# define __THROW __attribute__ ((__nothrow__))# define __NTH(fct) __attribute__ ((__nothrow__)) fct# else# if defined __cplusplus && __GNUC_PREREQ (2,8)# define __THROW throw ()# define __NTH(fct) fct throw ()# else# define __THROW# define __NTH(fct) fct# endif# endif#else /* Not GCC. */# define __inline /* No inline functions. */# define __THROW# define __NTH(fct) fct# define __const const# define __signed signed# define __volatile volatile#endif /* GCC. */
位置:/usr/include/features.h如果当前版本低于<maj.min>则为1。/* Convenience macros to test the versions of glibc and gcc.Use them like this:#if __GNUC_PREREQ (2,8)... code requiring gcc 2.8 or later ...#endifNote - they won't work for gcc1 or glibc1, since the _MINOR macroswere not defined then. */#if defined __GNUC__ && defined __GNUC_MINOR__# define __GNUC_PREREQ(maj, min) \((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))#else# define __GNUC_PREREQ(maj, min) 0#endif
上面的定义可以看出,__THROW宏定义只在GCC下有效,观察#ifdef __GNUC__部分,可以看出,在一般C环境中此宏是没有意义的;在GNUC版本高于3.2时,库用函数属性将C函数标记为__nothrow__;而如果代码定义了__cplusplus则表示为C++代码,且GNUC版本为2.8.x,此时才有意思,为C++程序加入throw()以优化函数调用。
总而言之,这个宏在C中没有什么大用。
关键字__attribute__允许你声明时指定特殊的属性。这个关键字后面跟着双层括号引起来的属性说明。目前定义用于函数的属性:
alignedalloc_sizealloc_alignassume_alignednoreturnreturns_twicenoinlinenocloneno_icfalways_inlineflattenpureconstnothrowsentinelformatformat_argno_instrument_functionno_split_stacksectionconstructordestructorusedunuseddeprecatedweakmallocaliasifuncwarn_unused_resultnonnullreturns_nonnullgnu_inlineexternally_visiblehotcoldartificialno_sanitize_addressno_address_safety_analysisno_sanitize_threadno_sanitize_undefinedno_reorderbnd_legacybnd_instrumentstack_protecterrorwarning
Other attributes, including section are supported for
variablesdeclarations,labelsand fortypes.You may also specify attributes with ‘__’ preceding and following each keyword. This allows you to use them in header files without being concerned about a possible macro of the same name. For example, you may use __noreturn__ instead of noreturn.
上面意思是说:你可以用__前缀和后缀在每个关键字上,这样你在头文件中使用时就不用担心可能存在同样名字宏的冲突。如__noreturn__替代noreturn。
__nonnull的宏定义在/usr/include/sys/cdefs.h里面:
/* The nonull function attribute allows to mark pointer parameters whichmust not be NULL. */#if __GNUC_PREREQ (3,3)# define __nonnull(params) __attribute__ ((__nonnull__ params))#else# define __nonnull(params)#endif
如果当前版本低于3.3,则__nonnull实际就是__nonnull__属性。Using the GNU Compiler Collection 中有关于nonnull的详细描述。
nonnull (arg-index, ...)
The nonnull attribute specifies that some function parameters should be nonnull
pointers. For instance, the declaration:extern void *
my_memcpy (void *dest, const void *src, size_t len)
__attribute__((nonnull (1, 2)));causes the compiler to check that, in calls to my_memcpy, arguments dest and
src are non-null. If the compiler determines that a null pointer is passed in
an argument slot marked as non-null, and the ‘-Wnonnull’ option is enabled, a
warning is issued. The compiler may also choose to make optimizations based
on the knowledge that certain function arguments will never be null.
If no argument index list is given to the nonnull attribute, all pointer arguments
are marked as non-null. To illustrate, the following declaration is equivalent to
the previous example:extern void *
my_memcpy (void *dest, const void *src, size_t len)
__attribute__((nonnull));
翻译一下:nonnull属性指定一些函数参数应为非空指针。举了一个例子,这个例子中__attribute__((nonnull (1, 2)))会引起编译器检查参数dest和src是否为非空。同时这个属性跟编译器选项-Wnonnull有联系,如果传入空指针到标记为非空的参数,且使能了-Wnonnull,编译器会报warning。另外如果不指定nonnull属性的参数索引号,则所有指针参数都被标记为非空。
__wur的宏定义在/usr/include/sys/cdefs.h里面:
/* If fortification mode, we warn about unused results of certainfunction calls which can lead to problems. */#if __GNUC_PREREQ (3,4)# define __attribute_warn_unused_result__ \__attribute__ ((__warn_unused_result__))# if __USE_FORTIFY_LEVEL > 0# define __wur __attribute_warn_unused_result__# endif#else# define __attribute_warn_unused_result__ /* empty */#endif#ifndef __wur# define __wur /* Ignore */#endif
在GCC版本小于3.4且__USE_FORTIFY_LEVEL>0时,__wur就是__attribute__ ((__warn_unused_result__))。
warn_unused_result
The warn_unused_result attribute causes a warning to be emitted if a caller of
the function with this attribute does not use its return value. This is useful for
functions where not checking the result is either a security problem or always
a bug, such as realloc.
int fn () __attribute__ ((warn_unused_result));int foo (){if (fn () < 0) return -1;fn ();return 0;}results in warning on line 5.
如果函数的调用者不使用函数的返回值,warn_unused_result属性会导致发出警告。这对于没检查函数结果是安全问题或是bug的函数很有帮助。
C库函数里面的很多宏最后都是属性(Attribute)的定义,且基本定义在/usr/include/sys/cdefs.h,关于不同的属性用法,可以参考Using the GNU Compiler Collection的第六章:Extensions to the C Language Family。
参考阅读:
__attribute_pure__带来的奇怪问题
Declaring Attributes of Functions