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.
Related
When I compile this code with gcc 7.3.0, I get an "assignment from incompatible pointer type".
int intVar = 1;
char* charPointer;
charPointer = &intVar;
printf("%d", *charPointer);
So far so good. I can deal with it by doing the pointer assignment this way:
charPointer = (char*)&intVar;
Now my doubt is: how is the second case different? I can still mess things up if I don't cast charPointer to int* when I, for example increment it by n or dereference it. So why does the compiler act differently in those two cases? Why should he care if pointer type does not match during an assignment? I would just like to understand the logic behind it.
Because of the casual type change int * to char *, the compiler warns of potential pitfalls. With a cast, the compiler assumes the coders know what they are doing.
In C, the various type of pointers can live in different places, have different sizes and be encoded differently.
It is very common for all object pointers (int*, char *, struct foo *) to share the same size and encoding, but, in general, that is not required.
In is not uncommon for Function pointers to be of a different size than object pointers.
char * and void * share the same size and encoding and character pointers point to data with a minimal alignment requirement. Converting a non-char* object pointer to char * always "work". The reverse is not always true. leading to undefined behavior (UB).
Converting to non-character pointer also risks anti-aliasing (the need for the compiler to keep track that changes of data via one pointer type is reflected in another). Very strange undefined behavior can result.>
Better code avoids pointer type changes1 and when needed, is explicit with a cast.
1 Exceptions include when changing an object pointer to void * or form void* when there is no alignment concerns.
Pointer conversions are kind of dangerous.
If the pointer type your converting from is insufficiently aligned for the target type, you get UB (==undefined behavior; read up on what it is unless you have already) already at the conversion.
Otherwise, if you get usually get UB on dereferencing because C's strict aliasing rules require that you access objects through lvalue types sufficiently compatible with their effective type.
While the last paragraph doesn't quite apply to conversions to char pointers as char pointers can alias any type, the warning (compilers could make it a hard error too) is still useful because the conversion is still kind of dangerous.
printf("%d", *(char*)&(int){0xFFFF});
will get you only the first byte (it is endianness dependent whether that is the most significant one or the least significant one), printing 255 (if the implementation's char type is unsigned) or -1 (if it is signed).
printf("%d", *&(int){0xFFFF});
will get you all the bytes that are in an int.
If the compiler lets you assign to a char * from an int * with just a warning, it should behave the same as with the cast, but you do need the cast for your C to be conformant (and for the compiler to be silent about the conversion).
As #Mike Holt says, it's not actually different, except that you have told the compiler "Don't worry, I mean to do this".
The compiler does worry because assigning to a pointer of a different type is usually not what you want to do. Your code is telling the compiler "Treat the memory holding this variable as if it were holding a variable of a different type". This is almost certainly platform specific behavior, and possibly undefined behavior, depending on the types.
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.
I am removing gcc warnings from a legacy code.
Is it possible to suppress the warning "cast to pointer from integer of different size" through typecasting:
example:
some_struct *ptr = func() // func() returns an integer.
Can someone please guide me how to resolve such gcc warnings?
First, if you can fix func (are allowed to modify its source), then fix it. If its computations can be done with pointers, then do them with pointers and return pointers. Sometimes there are valid reasons to work with addresses as integers (e.g., dealing with alignment issues in special code). In that case, change func to use the uintptr_t type (defined in stdint.h). It is designed for treating pointers as integers when necessary. (There is also intptr_t if signed arithmetic is better for some reason, but I generally find the unsigned uintptr_t to be less troublesome.) Preferably, func should convert the uintptr_t to a pointer when returning it, so the return type of func would be a pointer (to something, perhaps some_struct or void).
If you cannot fix func, then you can use casts to tell the compiler that you intend to do the conversions that are being performed. However, this particular error message is telling you that you are not merely converting an integer to a pointer, but that you are converting an integer of one size (e.g., four bytes) to a pointer of another size (e.g., eight bytes). It is likely this code was originally written for a system where the integer type returned by func had the same size as the pointer type, but you are now compiling on a system where the pointer type is larger or less than that integer size.
In that case, you must ensure that the computation performed by func works in the new architecture. If it is returning only a 32-bit value, will that always hold the correct value? That is, nothing will be lost by the missing high 32 bits? No address that func should calculate ever exceeds the maximum value of the integer type it uses? If func is using signed integer types, consider the sign bit too.
If you have ensured that the value returned by func is correct, then you can use explicit casts, such as: some_struct *ptr = (some_struct *) (intptr_t) func();.
My gcc does not give the warning you cited. It would also be strange because there is no cast in your code.
I get the warning
assignment makes pointer from integer without a cast
Note the "without a cast" part. Thus you can make gcc silent by casting (without changing the behaviour):
some_struct *ptr = (void*)func();
Then, you will get your warning ("cast to pointer from integer of different size") iff the return type of func does not fit for addresses. This can be silenced by additionally casting func() to a suitable integer type, e.g. intptr_t:
some_struct *ptr = (void*)(intptr_t)func();
All this under the assumption you really want to convert the wrong-sized integer to a pointer. Probably, reworking the code is a better idea.
There are two possibilities here:
func is casting an actual pointer to an integer; it is later used as a pointer.
func is returning an integer that is being stored in a pointer; ptr is later cast to an integer and used as an integer.
In the first case, the return value from func will lose information, and potentially crash or worse, if int is smaller than the size of a data pointer, which it will be on most 64-bit memory models (including Windows and Linux). In that case you should change the return type of func to intptr_t; see Using intptr_t instead of void*? and Why / when to use `intptr_t` for type-casting in C?.
In the second case, it's less of an issue but to deal with endianness issues you should cast through intptr_t: some_struct *ptr = (some_struct *)(intptr_t)func(); and later int value = (int)(intptr_t)ptr;. See GLib Type Conversion Macros for a discussion of the issue.
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.