【问题标题】:size of size_t preprocessor valuesize_t 预处理器值的大小
【发布时间】:2013-02-02 23:56:26
【问题描述】:

出于教育目的,我正在用 C 语言创建一个哈希表的实现。

散列函数应该返回一个 size_t 散列。由于 size_t 的大小在不同的平台上是不同的(并且我想使用一个散列函数来散列 size_t 中的所有位),我想为不同的大小创建不同的散列函数。由于哈希函数将用作函数指针,我怀疑编译器不能像这样内联代码:

size_t hash4(void* key, size_t size);
size_t hash8(void* key, size_t size);

size_t hash(void* key, size_t size)
{
    if (sizeof(size_t) == 4)
    {
        return hash4(key, size);
    }
    else if (sizeof(size_t) == 8)
    {
        return hash8(ket, size);
    }
}

size_t (*hashFunc)(void* key, size_t size) = hash;

并且每次调用散列函数时都会使用两级间接。

这就是为什么我想做这样的事情:size_t (*hashFunc)(void* key, size_t size) = hash##sizeof(size_t);。只会使用一级间接。问题是 sizeof 运算符在 prepossessing 阶段不可用。

那么定义一个预处理器值的好方法是什么,它将在每个平台上扩展到正确的 size_t 大小?我想我可以检查预定义的宏,但我想知道是否有更好的方法。

【问题讨论】:

  • 您的哈希函数很可能返回 uint32_t,这对于任何哈希表来说都足够了。

标签: c hash hashtable c-preprocessor size-t


【解决方案1】:

使用为许多编译器定义的 64 位检测宏,例如GCC 使用__x86_64

size_t hash(void* key, size_t size) {
   #ifdef __x86_64
       compute 64bit hash
   #else
       compute 32bit hash
   #endif
}

【讨论】:

  • 就此而言,如果您编写if (sizeof(size_t) == 8),那么在任何级别的优化下,发出的代码都不会真正执行测试,编译器将消除任何已死的分支。不过,您确实需要两个分支来编译。
【解决方案2】:

sizeof 是 C 运算符。 ## 是一个预处理器操作符。后者对前者一无所知。

因此,您最好使用一个宏来引用系统用于寻址的位宽,例如像这样进行测试:

#if UINTPTR_MAX == 0xffffffffffffffff
/* it's 64bits pointers */
#elif UINTPTR_MAX == 0xffffffff
/* it's 32bits pointers */
#endif

【讨论】:

  • 我知道我不能将 sizeof 用作预处理器运算符(我写了那个)。无论如何,我喜欢这个解决方案,我想我会与 eznme 的建议一起使用它。
【解决方案3】:

你可以这样做:

size_t (*hashFunc)(void* key, size_t size) = (sizeof(size_t) == 8) ? hash8 : hash4;

eznme 的方法也没有什么问题——编写一个根据size_t 的大小表现不同的函数。当然,前提是您在 64 位实现上不需要将 hash4 函数用于其他目的。

关于问题的标题——如果您在预处理器时绝对需要了解size_t,请使用stdint.h 中的SIZE_MAX 宏。

【讨论】:

  • 显然,我可以用它来初始化结构内的常量函数指针,所以我想我实际上更喜欢这个。
【解决方案4】:

那么定义一个预处理器值的好方法是什么,它将在每个平台上扩展到正确的 size_t 大小?

根据Glibc manual | Width of an Integer Type

TS 18661-1:2014 定义了整数类型宽度的宏( 值和符号位的数量)。这些宏的一个好处是它们 可以在 #if 预处理器指令中使用,而 sizeof 不能。这 以下宏在limits.h中定义。

CHAR_WIDTH
SCHAR_WIDTH
UCHAR_WIDTH
SHRT_WIDTH
USHRT_WIDTH
INT_WIDTH
UINT_WIDTH
LONG_WIDTH
ULONG_WIDTH
LLONG_WIDTH
ULLONG_WIDTH

这些是 char、signed char、unsigned char 类型的宽度, 短整数,无符号短整数,整数,无符号整数,长整数,无符号 分别是 long int、long long int 和 unsigned long long int。

更多此类宏在 stdint.h 中定义。除了那些为 由宽度指定的类型(参见整数),定义如下:

INTPTR_WIDTH
UINTPTR_WIDTH
PTRDIFF_WIDTH
SIG_ATOMIC_WIDTH
SIZE_WIDTH
WCHAR_WIDTH
WINT_WIDTH

这些是 intptr_t、uintptr_t、ptrdiff_t 类型的宽度, 分别为 sig_atomic_t、size_t、wchar_t 和 wint_t。

根据手册SIZE_WIDTH 是你要找的。​​p>

我不确定 MSVC、XLC 和 SunCC 等编译器是否可用;或 AIX、OX X、Solaris 或 Windows 等平台。

【讨论】:

  • IBM XLC for Linux 在 stdint.h 中定义 __SIZE_WIDTH__。此外,XLC for LinuxXLC for AIX 在 stdint.h 中定义 __SIZE_TYPE__
猜你喜欢
  • 2017-03-17
  • 1970-01-01
  • 2019-01-08
  • 1970-01-01
  • 2011-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多