Is it possible to pass intptr_t to a function that expects an int?

In particular, if I have the following type of function pointer:

typedef void (*callback_type) (intptr_t context, void* buffer, size_t count); 

Can I safely and without "undefined behavior" do:

 callback_type func_ptr = (callback_type)write; intptr_t context = fd; func_ptr(context, some_buffer, buffer_size); 

?

Where write() is the system call (EDIT: has the signature ssize_t write(int fd, const void *buf, size_t count); therefore, it takes int as the first argument), and fd is the file descriptor int . I assume that the answer will be the same for C and C ++, so I mark both.

+6
source share
3 answers

No

This will not be portable, because you are passing a parameter that will have a different size in the general LP64 paradigm.

In addition, you are not casting a function pointer with the correct type, and the results of this are undefined.

Now, as you seem to be done, the function pointer will work as expected and will be the only practical problem: how to write (2) interpret the first parameter intptr_t ?

And the actual runtime problem is that on LP64 you are passing a 64-bit value to a 32-bit parameter. This can lead to a bias in the following parameters. On a system with register parameters, this is likely to work fine.

+6
source

Let's look at standard C.

C11 (n1570), ยง 6.3.2.3 Indices

A pointer to a function of one type can be converted to a pointer to a function of another type and vice versa; the result is comparable to the original pointer. If a function whose type is not compatible with the reference type is used to call the converted pointer, the behavior is undefined.

C11 (n1570), ยง 6.7.6.3 Declaration of functions (including prototypes)

For two types of functions that must be compatible, both must indicate compatible return types. Moreover, the parameter list is listed, if both are present, agrees on the number of parameters and the use of the ellipsis terminator; corresponding parameters must have compatible types.

C11 (n1570), ยง 6.2.7 Compatible type and composite type

Two types have a compatible type if their types are the same.

Conclusion:

 void (*) (intptr_t context, void* buffer, size_t count); 

cannot be converted to:

 void (*) (int context, void* buffer, size_t count); 
+2
source

The problem is not to pass arguments between functions, as it automatically moves from one integral type to another.

The problem is that if intptr_t shorter than int , so not every int value can be represented by intptr_t ? In this case, some of the most significant bits in int will be truncated when converting to intptr_t , so you end write() ing in the wrong file descriptor. Although this should not cause undefined behavior, it is still erroneous.

+1
source

All Articles