Search code examples
cposixipc

What is the meaning of " ( void * ) " in : if ( test == ( void * ) -1 )


The function returns -1.

However, what is the meaning of (void*) in the following code:

can it work without it ?

test = shmat(shm_id, NULL, 0);

if (test == (void *)-1) {
    /* handle shmat failure */
}

Solution

  • shmat has the following prototype:

    void *shmat(int shmid, const void *shmaddr, int shmflg);
    

    i.e. it returns a pointer to void, not an integer.

    On error it will return the integer -1 cast to a pointer to void. From Linux manpages shmat(2):

    On success, shmat() returns the address of the attached shared memory segment; on error, (void *) -1 is returned, and errno is set to indicate the cause of the error.

    That is how you must do the comparison properly to check for an error return. The C11 standard says the following about the operator == in 6.5.9p5-6:

    5 Otherwise, at least one operand is a pointer. If one operand is a pointer and the other is a null pointer constant, the null pointer constant is converted to the type of the pointer.

    If one operand is a pointer to an object type and the other is a pointer to a qualified or unqualified version of void, the former is converted to the type of the latter.

    6 Two pointers compare equal if and only if both are null pointers, both are pointers to the same object (including a pointer to an object and a subobject at its beginning) or function, both are pointers to one past the last element of the same array object, or one is a pointer to one past the end of one array object and the other is a pointer to the start of a different array object that happens to immediately follow the first array object in the address space.109)

    That is, the standard defines behaviour for exactly 2 conversions: either one operand is a pointer to void, and the other operand is a pointer to something else; or one operand is a pointer, and the other operand is the null-pointer constant (i.e. 0, or (void*)0, or so). Since -1 without casts is neither a null-pointer constant, nor a pointer, the standard doesn't specify any behaviour for such case, thus the behaviour is undefined "by the omission of any explicit definition".

    test == -1 is wrong, and test == (void *) -1 is right(ish).

    As it turns out this is still a grey area. -1 is an int and on my computer, it is 32 bits. The conversion of an integer to pointer is defined by the implementation. The GCC manuals say:

    A cast from pointer to integer discards most-significant bits if the pointer representation is larger than the integer type, sign-extends[2] if the pointer representation is smaller than the integer type, otherwise the bits are unchanged.

    With footnote 2 saying

    Future versions of GCC may zero-extend, or use a target-defined ptr_extend pattern. Do not rely on sign extension.

    Thus it would mean that (void *)-1 might become incorrect too; the safer way would be to write it as (void *)(intptr_t)-1.


    For some reason the (void *)0, i.e. the null pointer, is not used to signal an error condition (even though use of such a pointer in C would be erroneous standard-wise).