Is it a good idea to use intptr_t as a general-purpose storage (to hold pointers and integer values) instead of void*? (As seen here: http://www.crystalspace3d.org/docs/online/manual/Api1_005f0-64_002dBit-Portability-Changes.html)
For what I've already read:
int -> void* -> int roundtrip is not guaranteed to hold original value; I guess int -> intptr_t -> int will do
pointer arithmetics on both void* and intptr_t require casts, so none gets advantage here
void* means less explicit casts when storing pointers, intptr_t means less casts when storing integer values
intptr_t requires C99
What else should I take into consideration?
Is it a good idea to use intptr_t as a general-purpose storage (to hold pointers and integer values) instead of void*?
No.
intptr_t is not guaranteed to exist. First, as you note, it was introduced in C99. Second, implementations are not required to have an integer type big enough to hold converted pointer values without loss of information.
Converting an int to intptr_t and back is unlikely to lose information but there's no actual guarantee that intptr_t is wider than int.
If you want to store pointer values, store them in pointer objects. That's what pointer objects are for.
Any pointer to an object or incomplete type can be converted to void* and back again without loss of information. There is no such guarantee for pointers to functions -- but any pointer-to-function type can be converted to any other pointer-to-function-type and back without loss of information. (I'm referring to the C standard; I think POSIX provides some additional guarantees.)
If you want to store either an integer or a pointer value in the same object, the first thing you should do is re-think your design. If you've already done so, and concluded that you really do want to do this, consider using a union (and keeping careful track of what kind of value you've stored most recently).
There are APIs that use a void* argument to allow arbitrary data to be passed; see, for example, the POSIX pthread_create() function. This can be abused by casting an integer value to void* but it's safer to pass the address of an integer object.
No, you can't be guaranteed that any particular type is a reasonable way of storing both pointers and integers, and besides, it makes your code confusing. There is a better way.
If you want to store an integer and a pointer in the same object, the clean and portable method is to use a union:
union foo {
int integer_foo;
void *pointer_foo;
};
This is portable and allows you to store both sorts of things in the size of storage needed for the larger of the two. It is guaranteed to always work.
Related
What standard-defined integer type should I use for holding pointer to functions? Is there a (void*)-like type for functions that can hold any functions?
It's very certain that it's not [u]intptr_t because the standard said explicitly it's for pointers to objects and the standard makes a clear distinction between pointer to objects and pointer to functions.
There is no specified type for an integer type that is sufficient to encode a function pointer.
Alternatives:
Change code to negate the need for that integer type. Rarely is such an integer type truly needed.
Use an array: unsigned char[sizeof( int (*)(int)) )] and int (*f)(int)) within union to allow some examination of the integer-ness of the pointer. Still there may be padding issues. Comes down to what code want to do with such an integer.
Use uintmax_t and hope it is sufficient. A _Static_assert(sizeof (uintmax_t) >= sizeof (int (*)(int)) ); is a reasonable precaution though not a guarantee of success.
The limiting spec
Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type. C17dr § 6.3.2.3 6
Note even [u]intptr_t for object pointer types are a guarantee either as they are optional types.
It's very certain that it's not [u]intptr_t
It's true. But the distinction is only made to guarantee the correctness of some essential conversions. If you look at the 2nd edition of "The C Programming Language", then the distinction is more subtle to notice than the current wording in the standard.
If you target platforms with operating systems, then [u]intptr_t is probably exactly what you want, as:
POSIX specifies dlsym function that returns void * with the requirement that result can be casted to function pointers and be usable.
Win32 GetProcAddress is defined in such way that, if the return values' not NULL, it'll be a valid memory address that's valid for functions and/or objects.
I'm porting a product to a CMSIS-based RTOS, and the product needs to obtain the thread ID as a 32-bit integer. However, the CMSIS thread id type (osThreadId) is completely opaque, typedef'd to struct os_thread_cb * with a comment that it can safely be changed to something else as.
So is there a safe device-independent way to get a thread-unique integer id? Can I assume, for example, that the pointer address itself will be unique and constant for each thread?
osThreadId is a pointer - pointers on Cortex-M are 32 bit, so casting to an 32 bit integer type is safe. As it is a pointer it the thread's control block, it will be entirely unique to that thread.
Since you are using CMSIS, it rather implies that target architecture, but in the general case to ensure portability to systems with perhaps different sized pointers, you could use uintptr_t declared in stdint.h. A typedef may be useful:
typedef uintptr_t tid_t
Then you can safely cast an osThreadId to a tid_t - either implicitly or explicitly.
Strictly uintptr_t is an integer type capable of holding a void* such that casting back to a void* it will compare as equal to the original pointer. Since any pointer type may be cast to and from void*, it is generally the case that a uintptr_t can hold any pointer, however if such things worry you, you could strictly cast to a void* before assigning to a uintptr_t - but in practice this is probably unnecessary and certainly so on Cortex-M.
I want to create a type to store pointers. The type should be compatible with C99 and have a fixed-width of 64 bits. I came up with several alternatives but they all seem flawed:
Using uint64_t is incorrect since conversions between pointers and integers are implementation-defined [C99 standard, 6.3.2.3].
uinptr_t also appears to be out of the picture, since the width of this type is not fixed and the type is optional anyway [7.18.1.4].
Using a struct such as
struct {
#ifdef __LP64__
void* ptr;
#else
// if big endian the following two fields need to be flipped
void* ptr;
uint32_t padding;
#endif
} fixed_ptr_type;
does not work either because the size of a pointer is not fixed even within the same implementation
Is there any C99-compatible definition of the type I'm looking for?
Object pointers
The best type to store object pointers is void *. Any object pointer can be converted to void * and back again.
Function pointers
A void * cannot necessarily store a function pointer. However, any function pointer can be converted to another type of function pointer, so you could store them in some arbitrary type (such as void (*)(void)).
Padding
I have no idea why you would need your pointer type to have a predetermined size, but you could pad them by using a union and hope that the result is not too large:
union fixed_ptr_type {
void *p;
char c[64/CHAR_BIT];
};
assert (CHAR_BIT * sizeof (union fixed_ptr_type) == 64);
I don't understand your objection to using the void * with padding. All objects of the same type have the same size. If a different object pointer type has a different size, that doesn't matter, because you convert it to void * to store it in your super-pointer.
Regarding uintptr_t: If it is not supported , then chances are that it's because there is actually no way of doing this on the particular platform.
So you could use uintptr_t. To add in the fixed-width requirement, you could cast to uintptr_t then to uint64_t (if you're happy with knowing you'll have to change your code when someone puts out a system that has pointers greater than 64bits!)
You cannot portably store pointer values in a 64-bit type. It's perfectly legal for an implementation to use 128-bit pointers.
If you don't mind losing portability to systems with pointers bigger than 64 bits, you can probably get away with using uint64_t. Conversions from pointer types to uint64_t are not guaranteed to work correctly without losing information, but they will almost certainly do so on any reasonable systems where pointers are no wider than 64 bits.
If an implementation has no 64-bit unsigned integer type without padding bits, then it will not define uint64_t at all (for example, a system with 9-bit bytes would not be able to implement uint64_t). There's a type uint_least64_t that's guaranteed, as the name implies, to be at least 64 bits wide; it will be exactly 64 bits on most systems, and wider than 64 bits only on systems where uint64_t doesn't exist.
uintptr_t is guaranteed to hold a converted void* value without loss of information, but it's not guaranteed to exist -- and if it doesn't exist, then no integer type can hold a converted void* value without loss of information. A conforming implementation needn't necessarily have any integer type that can hold a pointer value without loss of information.
Function pointers are another matter. Conversion from a function pointer to void*, or to any integer type, has undefined behavior (because the standard doesn't say what the behavior should be).
There simply is no 100% portable way to do what you're trying to do. You'll just have to settle for 99.9% portability. If you're not concerned with function pointers, I'd suggest using uint64_t (perhaps defining your own typedef to make it clear what you're doing) and add a compile-time or run-time check to confirm that sizeof (void*) <= sizeof (uint64_t). That should cover every existing implementation that I've ever heard of.
It might be helpful to know what your actual goal is. Why do you want to store pointers in no more or less than 64 bits? What problem does this solve that storing them in void* objects doesn't solve?
Incidentally, the __LP64__ macro that you mention in your question is non-standard.
I'm using a library which has a function with the following signature:
void LED_stop_blink_task ( void * callback_parameter );
The actual parameter the void pointer stands for is a pointer to uint32_t, which is the number of the led on the board.
Is there a way to call this function without using a variable to hold the data ?
In my imagination it will be like
LED_stop_blink_task(&35);
or the only way is like this:
uint32_t led_num = 35;
LED_stop_blink_task(&led_num);
If you're asking why I want to throw the variable away, well, I'm just curious if it's possible...
On most platforms it's possible to simply stuff the int in a void *:
LED_stop_blink_task((void *)32);
Then in the function you can cast to int.
An integer may be converted to any pointer type. Except as
previously specified, the result is implementation-defined, might not
be correctly aligned, might not point to an entity of the referenced
type, and might be a trap representation.
Any pointer type may be converted to an integer type. Except as
previously specified, the result is implementation-defined. If the
result cannot be represented in the integer type, the behavior is
undefined. The result need not be in the range of values of any integer
type.
In practice this will work on any POSIX-supported platform. For example TLPI says:
Strictly speaking, the C standards don’t define the results of casting
int to void * and vice versa. However, most C compilers permit these
operations, and they produce the desired result; that is, int j ==
(int) ((void *) j).
Cnicutar's answer is almost perfect; let me extend it with that it's not really portable - int is not guaranteed to be of the same size (or smaller) than a pointer, so you should use intptr_t or uintptr_t instead.
What does the following expression mean?
unsigned char *res = malloc(5);
Now I cast res:
(long)res
What does this casting mean?
Using that value will interpret the address to which res points (which is just a number anyway) as a long.
It will work most of the time but it's not completely okay (depends a lot on how you're using it). For example if you simply want to print it, you can get away with
printf("%p", res);
As a rule of thumb: treat any cast with suspicion.
The allocated memory is not read, you're just casting the pointer to the memory to a long.
This doesn't directly answer your question but is a useful bit of information that is more-or-less relevant to your siutation.
A cast from a pointer type to an integer type is implementation defined (that means the implementation decides what happens when you cast a pointer to an integer). C99 implementations that do support some type of reversible conversion should also provide two types found in <stdint.h> specifically for converting pointers to integers, namely uintptr_t and intptr_t. If your implementation provides these two types, then you can safely convert a pointer to these types and back to the original pointer type.
Since these types are implementation defined, you will need to check your implementations documentation for what the underlying types are.