I would like to compute the number of bytes between two addresses.
uint32_t length = &b - &a;
When a and b are uint32_t, length is 1.
uint32_t a, b;
uint32_t length = &b - &a; // length is one
When a and b are uint8_t, length is 4.
uint8_t a, b;
uint32_t length = &b - &a; // length is four
The computation, therefore, is the number of uint32_t or uint8_t between a and b, not the mathematical difference between the addresses as I falsely expected.
My question: What part of the C language covers computation of addresses? Can someone reference a location in the spec that discusses the topic?
Pointer subtraction is covered in section 6.5.6 of the C standard:
3 For subtraction, one of the following shall hold:
both operands have arithmetic type;
both operands are pointers to qualified or unqualified versions of compatible complete object types; or
the left operand is a pointer to a complete object type and the right operand has integer type.
...
9 When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array
object; the result is the difference of the subscripts of the two
array elements. The size of the result is implementation-defined, and
its type (a signed integer type) is ptrdiff_t defined in the
header. If the result is not representable in an object of
that type, the behavior is undefined. In other words, if the
expressions P and Q point to, respectively, the i-th and j-th elements
of an array object, the expression (P)-(Q) has the value i−j provided
the value fits in an object of type ptrdiff_t. Moreover, if the
expression P points either to an element of an array object or one
past the last element of an array object, and the expression Q points
to the last element of the same array object, the expression
((Q)+1)-(P) has the same value as ((Q)-(P))+1 and as -((P)-((Q)+1)),
and has the value zero if the expression P points one past the last
element of the array object, even though the expression (Q)+1 does not
point to an element of the array object.
So the difference is the number of elements between the two, not the number of bytes.
Note that this only allows subtracting pointers between two elements of the same array. So this is legal:
uint32_t a[5];
uint32_t len = &a[1] - &a[0];
But this is not:
uint32_t a, b
uint32_t len = &b - &a;
in the standard compliant C pointer arithmentics is not allowed if the pointers have different types or not point to the same memory block (ie table or allocated other way). Otherwise it is the UB
But if the variables are located in the same continuous address space - for example in the ARM uC result of this arithmetics will be defined if pointes have the same type or you cast them to the same type.
this is nor C standard compliant code
#include <stdio.h>
#include <stdint.h>
uint64_t c;
uint64_t d;
uint16_t e;
uint8_t f;
int main(void)
{ uint32_t a,b;
printf("%lld\n", (long long)((uint8_t *)&b - (uint8_t *)&a));
printf("%lld\n", (long long)((uint8_t *)&c - (uint8_t *)&a));
printf("%lld\n", (long long)((uint8_t *)&d - (uint8_t *)&c));
printf("%lld\n", (long long)((uint8_t *)&e - (uint8_t *)&d));
printf("%lld\n", (long long)((uint8_t *)&f - (uint8_t *)&c));
}
What will be printed is 100% up to implementation. Some of the results might have sense another not.
This kind of arithmetic is used in the embedded development for example by defining the symbols in the linker script (for example start of bss and end of bss) and then those symbols (their addresses actually) are used to do something like zeroing the bss or initializing the data segment
You can try it on Linux machine:
https://ideone.com/dm0R5M
I would like to compute the number of bytes between two addresses.
If the addresses are in the same array, code can subtract pointers to get a count of the number of elements in the difference. Then multiply by the size of the type to report the number of "bytes".
ptrdiff_t diff = &a[some_index] - &a[some__other_index];
diff *= sizeof a[0];
printf("Diff %td\n", diff);
If the address of 2 objects are not known to be in the same array, code can carefully subtract, yet depending on the memory model, the difference may or may not represent the "byte" difference. IAC, the below avoids undefined behavior.
#include <inttypes.h>
#include <stdio.h>
void *va = &a;
void *vb = &b;
// optional types
uintptr_t ua = (uintptr_t)va;
uintptr_t ub = (uintptr_t)vb;
uintptr_t diff = ua > ub ? ua - ub : ub - ua;
printf("Maybe byte difference of %" PRIuPTR "\n", diff);
Related
Why doesn't typecasting work here..?
#include<stdio.h>
int main(){
int x = 5;
float y = 7.0;
float *p = &y;
int *q = &x;
printf("p is %d\nq is %d\np - q is %d", p, q, (p - q));
return 0;
}
I am getting this error invalid operands of types 'float*' and 'int*' to binary 'operator-'; what does it mean?
The error means that the compiler is unable to deduce the common type of two operands one of which has the type float * and other int *. There is no implicit conversion between these types.
But in any case the program has undefined behavior because at least you may not subtract two pointers that do not point to elements of the same array or to a memory after the last element of the same array.
From the C Standard (6.5.6 Additive operators)
9 When two pointers are subtracted, both shall point to elements of
the same array object, or one past the last element of the array
object; the result is the difference of the subscripts of the two
array elements.
And using incorrect conversion specifiers (as for example %d with a pointer) for supplied arguments in the function printf also invokes undefined behavior.
From the C Standard (7.21.6.1 The fprintf function)
9 If a conversion specification is invalid, the behavior is
undefined.275) If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.
I suppose you want to subtract the actual values your pointers are pointing to.
C converts int to float implicitly when you are operating on float and int.
Also, you program has some problems as
Not using %f type specifier to print float pointer
Not using the * operator to access pointer values.
Here is your program, working:
#include <stdio.h>
int main()
{
int x = 5;
float y = 7.0;
float *p = &y;
int *q = &x;
printf("p is %f\nq is %d\np - q is %f", *p, *q, (*p - *q));
return 0;
}
With the outputs:
p is 7.000000
q is 5
p - q is 2.000000
You can't subtract pointers like that and get a meaningful result in standard C.
Per 6.5.6 Additive operators, paragraph 9 of the C11 standard:
When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements.
In this case, a single int or float variable is considered to be an array of size 1.
So given
int x = 5;
float y = 7.0;
float *p = &y;
int *q = &x;
trying to compute the value p - q results in undefined behavior.
Per J.2 Undefined behavior:
The behavior is undefined in the following circumstances:
...
Pointers that do not point into, or just beyond, the same array object are subtracted
However, code like this likely won't cause problems as it's merely subtracting two integer values (although I haven't checked thoroughly), but the result doesn't have to be meaningful:
int x = 5;
float y = 7.0;
float *p = &y;
int *q = &x;
intptr_t diff = ( intptr_t ) p - ( intptr_t ) q;
Edit: As has been pointed out in the comments, subtracting two void* pointers is not proper standard C. If you want to subtract two pointers to find the distance between them the correct approach is to cast them to an appropriately sized integer, and then do integer arithmetic.
E.g.:
printf("p is %p\nq is %p\np - q is %ld\n", p, q, ((intptr_t)p - (intptr_t)q));
Original answer:
It means that the minus operator is not defined for mixed types of pointers. If you want to subtract those two pointers, for example to find the amount of space between them, the better option would be to cast them both to void* pointers.
Also, you should print pointer values with the %p specifier instead of %d.
E.g.:
printf("p is %p\nq is %p\np - q is %ld\n", p, q, ((void*)p - (void*)q));
I was expecting the code below to print 4 (since a float is 4 bytes), but it prints 1. Would someone explain why this happens?
#include <stdio.h>
int main()
{
float a[4]={0.0,0.1,0.2,0.3};
printf("%d", &a[1]-&a[0]);
return 0;
}
First of all, change
printf("%d", &a[1]-&a[0]);
to
printf("%td", &a[1]-&a[0]);
as the result type of two subtraction yields a type ptrdiff_t and %td is the conversion specifier for that type.
That said, quoting C11, chapter §6.5.6, subtraction operator (emphasis mine)
When two pointers are subtracted, both shall point to elements of the same array object,
or one past the last element of the array object; the result is the difference of the
subscripts of the two array elements. [....] In
other words, if the expressions P and Q point to, respectively, the i-th and j-th elements of
an array object, the expression (P)-(Q) has the value i−j provided the value fits in an object of type ptrdiff_t. [....]
In your case, P is &a[1] and Q is &a[0], so i is 1 and j is 0. Hence the result of the subtraction operation is i-j, i.e., 1-0, 1.
You are correct that the two pointers are 4 bytes apart. And if you were subtracting two integers you'd get 4. But &a[1] and &a[0] are of type float *. Pointer arithmetic in C takes into account the size of the thing being pointed to, so &a[1]-&a[0] is 1.
This is the basic means by which array indexing works. You can take advantage of this to iterate through an array without needing a separate index and instead terminating on a boundary such as NaN.
#include <stdio.h>
#include <math.h>
int main()
{
float a[] = { 0.0,0.1,0.2,0.3,NAN };
float *iter = a;
while(!isnan(*iter)) {
printf("%f\n", *iter);
iter++;
}
}
If you instead cast the values to unsigned int you will indeed get 4.
printf("%u\n", (unsigned int)&a[1]-(unsigned int)&a[0]);
Let's say I have this code that copies one block of memory to another in a certain order based on their location:
void *my_memmove(void *dest, const void *src, size_t len)
{
const unsigned char *s = (const unsigned char *)src;
unsigned char *d = (unsigned char *)dest;
if(dest < src)
{
/* copy s to d forwards */
}
else
{
/* copy s to d backwards */
}
return dest;
}
This is undefined behavior if src and dest do not point to members of the same array(6.8.5p5).
However, let's say I cast these two pointers to uintptr_t types:
#include <stdint.h>
void *my_memmove(void *dest, const void *src, size_t len)
{
const unsigned char *s = (const unsigned char *)src;
unsigned char *d = (unsigned char *)dest;
if((uintptr_t)dest < (uintptr_t)src)
{
/* copy s to d forwards */
}
else
{
/* copy s to d backwards */
}
return dest;
}
Is this still undefined behavior if they're not members of the same array? If it is, what are some ways that I could compare these two locations in memory legally?
I've seen this question, but it only deals with equality, not the other comparison operators (<, >, etc).
The conversion is legal but there is, technically, no meaning defined for the result. If instead you convert the pointer to void * and then convert to uintptr_t, there is slight meaning defined: Performing the reverse operations will reproduce the original pointer (or something equivalent).
It particular, you cannot rely on the fact that one integer is less than another to mean it is earlier in memory or has a lower address.
The specification for uintptr_t (C 2018 7.20.1.4 1) says it has the property that any valid void * can be converted to uintptr_t, then converted back to void *, and the result will compare equal to the original pointer.
However, when you convert an unsigned char * to uintptr_t, you are not converting a void * to uintptr_t. So 7.20.1.4 does not apply. All we have is the general definition of pointer conversions in 6.3.2.3, in which paragraphs 5 and 6 say:
An integer may be converted to any pointer type. Except as previously specified [involving zero for null pointers], 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 [null pointers again], 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.
So these paragraphs are no help except they tell you that the implementation documentation should tell you whether the conversions are useful. Undoubtedly they are in most C implementations.
In your example, you actually start with a void * from a parameter and convert it to unsigned char * and then to uintptr_t. So the remedy there is simple: Convert to uintptr_t directly from the void *.
For situations where we have some other pointer type, not void *, then 6.3.2.3 1 is useful:
A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.
So, converting to and from void * is defined to preserve the original pointer, so we can combine it with a conversion from void * to uintptr_t:
(uintptr_t) (void *) A < (uintptr_t) (void *) B
Since (void *) A must be able to produce the original A upon conversion back, and (uintptr_t) (void *) A must be able to produce its (void *) A, then (uintptr_t) (void *) A and (uintptr_t) (void *) B must be different if A and B are different.
And that is all we can say from the C standard about the comparison. Converting from pointers to integers might produce the address bits out of order or some other oddities. For example, they might produce a 32-bit integer contain a 16-bit segment address and a 16-bit offset. Some of those integers might have higher values for lower addresses while others have lower values for lower addresses. Worse, the same address might have two representations, so the comparison might indicate “less than” even though A and B refer to the same object.
No. Each results in an implementation-defined value, and comparison of integers is always well-defined (as long as their values are not indeterminate). Since the values are implementation-defined, the result of the comparison need not be particularly meaningful in regard to the pointers; however, it must be consistent with the properties of integers and the values that the implementation-defined conversions produced. Moreover, the C standard expresses an intent that conversions of pointers to integers should respect the address model of the implementation, making them somewhat meaningful if this is followed. See footnote 67 under 6.3.2.3 Pointers:
The mapping functions for converting a pointer to an integer or an integer to a pointer are intended to be consistent with the addressing structure of the execution environment.
However, some current compilers wrongly treat this as undefined behavior, at least under certain conditions, and there is a movement from compiler folks to sloppily formalize that choice via a notion of "provenance", which is gratuitously internally inconsistent and a disaster in the making (it could be made internally consistent and mostly non-problematic with trivial changes that are cost-free to code where it matters, but the people who believe in this stuff are fighting that for Reasons(TM)).
I'm not up-to-date on the latest developments in the matter, but you can search for "pointer provenance" and find the draft documents.
Comparing two pointers converted to uintptr_t should not have undefined behaviour at all. It does not even should have unspecified behaviour. Note that you should first cast the values to void * to ensure the same presentation, before casting to uintptr_t. However, compilers have had behaviour where two pointers were deemed to be unequal even though they pointed to the same address, and likewise, these pointers cast to uintptr_t compared unequal to each other (GCC 4.7.1 - 4.8.0). The latter is however not allowed by the standard. However there is *ongoing debate on the extent of pointer provenance tracking and this is part of it.
The intent of the standard according to C11 footnote 67 is that this is "to be consistent with the addressing structure of the execution environment". The conversion from pointer to integer is implementation-defined and you must check the implementation for the meaning of the cast. For example for GCC, it is defined as follows:
The result of converting a pointer to an integer or vice versa (C90
6.3.4, C99 and C11 6.3.2.3).
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.
A cast from integer to pointer discards most-significant bits if the
pointer representation is smaller than the integer type, extends
according to the signedness of the integer type if the pointer
representation is larger than the integer type, otherwise the bits are
unchanged.
When casting from pointer to integer and back again, the resulting
pointer must reference the same object as the original pointer,
otherwise the behavior is undefined. That is, one may not use integer
arithmetic to avoid the undefined behavior of pointer arithmetic as
proscribed in C99 and C11 6.5.6/8.
For example on x86-32, x86-64 and GCC we can be assured that the behaviour of a pointer converted to uintptr_t is that the linear offset is converted as-is.
The last clause refers to pointer provenance, i.e. the compiler can track the identity of pointer stored in an (u)intptr_t, just like it can track the identity of a pointer in any other variable. This is totally allowed by C standard as it states just that you are ever guaranteed to be able to cast a pointer to void to (u)intptr_t and back again.
I.e.
char foo[4] = "abc";
char bar[4] = "def";
if (foo + 4 == bar) {
printf("%c\n", foo[4]); // undefined behaviour
}
and given that foo + 4 compares equal to bar (allowed by the C standard), you cannot dereference foo[4] because it does not alias bar[0]. Likewise even if foo + 4 == bar you cannot do
uintptr_t foo_as_int = (uintptr_t)(void *)foo;
if (foo_as_int + 4 == (uintptrt_t)(void *)bar) {
char *bar_alias = (void *)(foo_as_int + 4);
printf("%c\n", bar_alias[0]); // undefined behaviour
}
There is no guarantee that the numeric value produced by converting a pointer to uintptr_t have any meaningful relationship to the pointer in question. A conforming implementation with enough storage could make the first pointer-to-integer conversion yield 1, the second one 2, etc. if it kept a list of all the pointers that were converted.
Practical implementations, of course, almost always perform pointer-to-uintptr_t conversions in representation-preserving fashion, but because the authors of the Standard didn't think it necessary to officially recognize a category of programs that would be portable among commonplace implementations for commonplace platforms, some people regard any such code as "non-portable" and "broken". This completely contradicts the intention of the Standard's authors, who made it clear that they did not wish to demean programs that were merely conforming but not strictly conforming, but it is unfortunately the prevailing attitude among some compiler maintainers who don't need to satisfy customers in order to get paid.
No, it's only implementation-defined behavior. However, if you use == to make sure the objects overlap before comparing them with < or >, then it is neither implementation-defined behavior or undefined behavior. This is how you would implement such a solution:
#include <string.h>
void *my_memmove(void *dest, const void *src, size_t len)
{
const unsigned char *s = src;
unsigned char *d = dest;
size_t l;
if(dest == src)
goto end;
/* Check for overlap */
for( l = 0; l < len; l++ )
{
if( s + l == d || s + l == d + len - 1 )
{
/* The two objects overlap, so we're allowed to
use comparison operators. */
if(s > d)
{
/* copy forwards */
break;
}
else /* (s < d) */
{
/* copy backwards */
s += len;
d += len;
while(len--)
{
*--d = *--s;
}
goto end;
}
}
}
/* They don't overlap or the source is after
the destination, so copy forwards */
while(len--)
{
*s++ = *d++;
}
end:
return dest;
}
I am failing to understand what the expression *(uint32_t*) does.
I have broken the statement down to an example that declares the parts so I can try and interpret what each one does.
uint32_t* ptr;
uint32_t num
*(uint32_t*)(ptr + num); // <-- what does this do?
I don't understand the last bit in the example, what happens when the expression *(uint32_t*)(ptr + num); executes during runtime?
uint32_t is a numeric type that guarantees 32 bits. The value is unsigned, meaning that the range of values goes from 0 to 232 - 1.
This
uint32_t* ptr;
declares a pointer of type uint32_t*, but the pointer is uninitialized, that
is, the pointer does not point to anywhere in particular. Trying to access memory through that pointer will cause undefined behaviour and your program might crash.
This
uint32_t num;
is just a variable of type uint32_t.
This
*(uint32_t*)(ptr + num);
ptr + num returns you a new pointer. It is called pointer arithmetic. It's like regular arithmetic, only that compiler takes the size of types into
consideration. Think of ptr + num as the memory address based on the original ptr pointer plus the number of bytes for num uint32_t objects.
The (uint32_t*) x is a cast. This tells the compiler that it should treat the expression x as if it were a uint32_t*. In this case, it's not even needed,
because ptr + num is already a uint32_t*.
The * at the beginning is the dereferencing operator which is used to access the memory through a pointer. The whole expression is equivalent to
ptr[num];
Now, because none of these variables is initialized, the result will be garbage.
However, if you initialize them like this:
uint32_t arr[] = { 1, 3, 5, 7, 9 };
uint32_t *ptr = arr;
uint32_t num = 2;
printf("%u\n", *(ptr + num));
this would print 5, because ptr[2] is 5.
uint32_t is defined in stdint.h, so one may need to include it
#include <stdint.h>
this header shall define uint32_t to be an unsigned integer type taking exactly 32 bits.
This doesn't really do anything. Let me give you a different example:
uint32_t data;
void *pointer = &data;
*(uint32_t *)pointer = 5;
First of all, void* means "generic" pointer. It can point to objects of any type.
Now, (uint32_t *) means "interpret pointer as a pointer to an object with type uint32_t.
The rest of the expression simply means "store 5 at the location stored by this pointer".
If you want to know what uint32_t is, that's an unsigned integer with exactly 32 bits. And pointer + num is the same as the adress of pointer[5].
This type of expression is usually used in type punning. If you're not familiar with type punning, the main idea is to bypass the type system so that you can treat something as a different type than it really is (ie treat an int a as double)
The main idea behind type punning is you take a pointer to a current variable and then pun it into a different type by casting it into a pointer of that type and then dereferencing it, hence the commonly used cast and dereference you are referring to ( *(uint32_t *) = cast to unsigned 32bit int pointer and then dereference).
As others have pointed out, your code "does nothing" because you are punning an int to an int, which has no effect. If you wanted to pun an int into a double however...
uint32_t num=5;
double& myvar=*(double*) #
Now you can manipulate nums memory as a double via myvar even though num is still an Int. This is a terrible idea and is just meant as a toy example of the use of punning.
I would like to know if there is a difference between:
Casting a primitive variable to another primitive type
Dereferencing a cast of a primitive variable's address to a pointer of another primitive type
I would also like to know if there is a good reason to ever use (2) over (1). I have seen (2) in legacy code which is why I was wondering. From the context, I couldn't understand why (2) was being favored over (1). And from the following test I wrote, I have concluded that at least the behavior of an upcast is the same in either case:
/* compile with gcc -lm */
#include <stdio.h>
#include <math.h>
int main(void)
{
unsigned max_unsigned = pow(2, 8 * sizeof(unsigned)) - 1;
printf("VALUES:\n");
printf("%u\n", max_unsigned + 1);
printf("%lu\n", (unsigned long)max_unsigned + 1); /* case 1 */
printf("%lu\n", *((unsigned long *)&max_unsigned) + 1); /* case 2 */
printf("SIZES:\n");
printf("%d\n", sizeof(max_unsigned));
printf("%d\n", sizeof((unsigned long)max_unsigned)); /* case 1 */
printf("%d\n", sizeof(*((unsigned long *)&max_unsigned))); /* case 2 */
return 0;
}
Output:
VALUES:
0
4294967296
4294967296
SIZES:
4
8
8
From my perspective, there should be no differences between (1) and (2), but I wanted to consult the SO experts for a sanity check.
The first cast is legal; the second cast may not be legal.
The first cast tells the compiler to use the knowledge of the type of the variable to make a conversion to the desired type; the compiler does it, provided that a proper conversion is defined in the language standard.
The second cast tells the compiler to forget its knowledge of the variable's type, and re-interpret its internal representation as that of a different type *. This has limited applicability: as long as the binary representation matches that of the type pointed by the target pointer, this conversion will work. However, this is not equivalent to the first cast, because in this situation value conversion never takes place.
Switching the type of the variable being cast to something with a different representation, say, a float, illustrates this point well: the first conversion produces a correct result, while the second conversion produces garbage:
float test = 123456.0f;
printf("VALUES:\n");
printf("%f\n", test + 1);
printf("%lu\n", (unsigned long)test + 1);
printf("%lu\n", *((unsigned long *)&test) + 1); // Undefined behavior
This prints
123457.000000
123457
1206984705
(demo)
* This is valid only when one of the types is a character type and the pointer alignment is valid, type conversion is trivial (i.e. when there is no conversion), when you change qualifiers or signedness, or when you cast to/from a struct/union with the first member being a valid conversion source/target. Otherwise, this leads to undefined behavior. See C 2011 (N1570), 6.5 7, for complete description. Thanks, Eric Postpischil, for pointing out the situations when the second conversion is defined.
Let's look at two simple examples, with int and float on modern hardware (no funny business).
float x = 1.0f;
printf("(int) x = %d\n", (int) x);
printf("*(int *) &x = %d\n", *(int *) &x);
Output, maybe... (your results may differ)
(int) x = 1
*(int *) &x = 1065353216
What happens with (int) x is you convert the value, 1.0f, to an integer.
What happens with *(int *) &x is you pretend that the value was already an integer. It was NOT an integer.
The floating point representation of 1.0 happens to be the following (in binary):
00111111 100000000 00000000 0000000
Which is the same representation as the integer 1065353216.
This:
(type)variable
takes the value of variable and converts it to type type. This conversion does not necessarily just copy the bits of the representation; it follows the language rules for conversions. Depending on the source and target types, the result may have the same mathematical value as variable, but it may be represented completely differently.
This:
*((type *)&variable)
does something called aliasing, sometimes informally called type-punning. It takes the chunk of memory occupied by variable and treats it as if it were an object of type type. It can yield odd results, or even crash your program, if the source and target types have different representations (say, an integer and a floating-point type), or even if they're of different sizes. For example, if variable is a 16-bit integer (say, it's of type short), and type is a 32-bit integer type, then at best you'll get a 32-bit result containing 16 bits of garbage -- whereas a simple value conversion would have given you a mathematically correct result.
The pointer cast form can also give you alignment problems. If variable is byte-aligned and type requires 2-byte or 4-byte alignment, for example, you can get undefined behavior, which could result either in a garbage result or a program crash. Or, worse yet, it might appear to work (which means you have a hidden bug that may show up later and be very difficult to track down).
You can examine the representation of an object by taking its address and converting it to unsigned char*; the language specifically permits treating any object as an array of character type.
But if a simple value conversion does the job, then that's what you should use.
If variable and type are both arithmetic, the cast is probably unnecessary; you can assign an expression of any arithmetic type to an object of any arithmetic type, and the conversion will be done implicitly.
Here's an example where the two forms have very different behavior:
#include <stdio.h>
int main(void) {
float x = 123.456;
printf("d = %g, sizeof (float) = %zu, sizeof (unsigned int) = %zu\n",
x, sizeof (float), sizeof (unsigned int));
printf("Value conversion: %u\n", (unsigned int)x);
printf("Aliasing : %u\n", *(unsigned int*)&x);
}
The output on my system (it may be different on yours) is:
d = 123.456, sizeof (float) = 4, sizeof (unsigned int) = 4
Value conversion: 123
Aliasing : 1123477881
What's the difference between “(type)variable” and “*((type *)&variable)”, if any?
The second expression may lead to alignment and aliasing issues.
The first form is the natural way to convert a value to another type. But assuming there is no violation of alignment or aliasing, in some cases the second expression has an advantage over the first form. *((type *)&variable) will yield a lvalue whereas (type)variable will not yield a lvalue (the result of a cast is never a lvalue).
This allows you do things like:
(*((type *)& expr)))++
See for example this option from Apple gcc manual which performs a similar trick:
-fnon-lvalue-assign (APPLE ONLY): Whenever an lvalue cast or an lvalue conditional expression is encountered, the compiler will issue a deprecation warning
and then rewrite the expression as follows:
(type)expr ---becomes---> *(type *)&expr
cond ? expr1 : expr2 ---becomes---> *(cond ? &expr1 : &expr2)
Casting the pointer makes a difference when working on a structure:
struct foo {
int a;
};
void foo()
{
int c;
((struct foo)(c)).a = 23; // bad
(*(struct foo *)(&c)).a = 42; // ok
}
First one ((type)variable is simple casting a variable to desired type and second one (*(type*)&variable) is derefencing a pointer after being casted by the desired pointer type.
The difference is that in the second case you may have undefined behavior. The reason being that unsinged is the same as unsigned int and an unsigned long may be larger than the the unsigned int, and when casting to a pointer which you dereference you read also the uninitialized part of the unsigned long.
The first case simply converts the unsigned int to an unsigned long with extends the unsigned int as needed.