Question

I am creating an implementation of a hash table in C for educational purposes.

The hash function should return a size_t hash. Since the size of size_t is different in different platforms (and I want to use a hash function that hashes all the bits in a size_t), I thought of creating different hash functions for different sizes. As the hash function will be used as a function pointer, I suspect the compiler can't inline code like this:

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;

And two levels of indirection will be used each time the hash function will be called.

That's why I thought of doing something like this: size_t (*hashFunc)(void* key, size_t size) = hash##sizeof(size_t); instead. Only one level of indirection will be used. The problem is that the sizeof operator isn't available during the prepossessing phase.

So what would be a good way to define a preprocessor value which will expand to the correct size of size_t in each platform? I guess I could check against predefined macros, but I wonder if there's a better way.

Was it helpful?

Solution 2

You could do this:

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

There's also nothing wrong with eznme's approach -- write a single function that behaves differently according to the size of size_t. Provided that you don't need the hash4 function for other purposes on 64bit implementations, of course.

Regarding the title of the question -- if you absolutely need to know about size_t at preprocessor time, then use the SIZE_MAX macro from stdint.h.

OTHER TIPS

sizeof is a C-operator. ## is a preprocessor operator. The latter does not know anything about the former.

So you might be better of using a macro referring to the system's bit-width used for addressing, like for example testing like so:

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

Use a 64-bit detecting macro like defined for many compilers, e.g. GCC uses __x86_64

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

So what would be a good way to define a preprocessor value which will expand to the correct size of size_t in each platform?

According to the Glibc manual | Width of an Integer Type:

TS 18661-1:2014 defines macros for the width of integer types (the number of value and sign bits). One benefit of these macros is they can be used in #if preprocessor directives, whereas sizeof cannot. The following macros are defined in limits.h.

CHAR_WIDTH
SCHAR_WIDTH
UCHAR_WIDTH
SHRT_WIDTH
USHRT_WIDTH
INT_WIDTH
UINT_WIDTH
LONG_WIDTH
ULONG_WIDTH
LLONG_WIDTH
ULLONG_WIDTH

These are the widths of the types char, signed char, unsigned char, short int, unsigned short int, int, unsigned int, long int, unsigned long int, long long int and unsigned long long int, respectively.

Further such macros are defined in stdint.h. Apart from those for types specified by width (see Integers), the following are defined:

INTPTR_WIDTH
UINTPTR_WIDTH
PTRDIFF_WIDTH
SIG_ATOMIC_WIDTH
SIZE_WIDTH
WCHAR_WIDTH
WINT_WIDTH

These are the widths of the types intptr_t, uintptr_t, ptrdiff_t, sig_atomic_t, size_t, wchar_t and wint_t, respectively.

According to the manual SIZE_WIDTH is what you are looking for.

I'm not sure of the availability with compilers like MSVC, XLC and SunCC; or platforms like AIX, OX X, Solaris or Windows.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top