1

I have tried finding an answer to this but I could not. Say I want to write a value at some specific address in memory. Say I want to write 7 at address 0x80005000.

So I do something like this:

uint32_t *ptr = (uint32_t* )0x80005000;
*ptr = 7;

What I don't understand is why do we need to typecast that hex value of the address to a pointer type. What can go wrong if we do it without the cast?

alinsoar
  • 15,386
  • 4
  • 57
  • 74
Cantaff0rd
  • 705
  • 1
  • 6
  • 14
  • 1
    Are you asking why it's not `uint32_t *ptr = 0x80005000;` (without the explicit cast) ? Or why it's not `uint32_t ptr = (uint32_t)0x80005000;` (without the pointer) ? – Sander De Dycker Apr 23 '19 at 06:31
  • How would you write a value at a specific address without indicating to the compiler that it is an address? The cast is used to indicate that. – P.W Apr 23 '19 at 06:37
  • I'm asking why it's not uint32_t *ptr = 0x80005000; Why do we need that cast there. @P.W but we can just assign the hex value to the pointer without casting it to pointer. I just checked. – Cantaff0rd Apr 23 '19 at 07:21
  • @Cantaff0rd No you cannot do that on a conforming C compiler. Try for example gcc in standard mode, `gcc -std=c11 -pedantic-errors` and you'll see that it won't let the code through. See the link above for an explanation. – Lundin Apr 23 '19 at 07:33
  • allright will do thanks – Cantaff0rd Apr 23 '19 at 09:31

2 Answers2

0

The type of 0x80005000 is (probably) int, which is not a pointer and can't be assigned to a pointer-type variable without casting (well technically it can, but the compiler should complain about it).

Casting the value tells the compiler "the type of this value is really something else than you think it is, so it's okay".

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • I understand that. But what could happen if we do not cast and ignore the compiler warning. Give me an example of something bad that could happen – Cantaff0rd Apr 23 '19 at 07:18
  • 2
    @Cantaff0rd Nothing bad might happen, or it might not work. It really depends on too many factors.And you should really treat all warnings as errors and never ignore them, it will make your life as a C programmer much easier in the long run. – Some programmer dude Apr 23 '19 at 07:26
  • 1
    Your boss could fire you for checking in code that breaks the build over a compiler warning. Bad things in programming are not restricted to the CPU. – Mark Benningfield Apr 23 '19 at 07:27
  • 4
    @Cantaff0rd The C standard only says that in case of C language violations, such as this one, the compiler must present a "diagnostic message". Errors and warnings are not terms defined by the standard. And so it is sufficient if the C compiler gives you a warning, as far as the standard is concerned. If you try to run the program still, it is either relying on non-standard extensions or undefined behavior. – Lundin Apr 23 '19 at 07:38
  • allright. thanks everyone for yoyur answers! – Cantaff0rd Apr 23 '19 at 09:32
  • `0x80005000` would not have type `int` on normal systems with 32-bit int, since it's larger than `INT_MAX` – M.M Apr 23 '19 at 13:12
  • @M.M It is actually `unsigned int` because of the peculiar rules for hex integer constants. – Lundin Apr 23 '19 at 13:17
0

Casting is basically a way to tell the compiler that "Yes, I'm sure what I'm doing and I will take responsibility for any consequences."

In your particular case, the main reason for the cast is to hush the compiler, so that it does not emit a warning. The code would compile (unless you compile with the parameter -pedantic-errors) and is not unlikely to work well without the cast.

However, do keep in mind that without the cast you will invoke undefined behavior. The C11 standard 6.5.16.1 says:

One of the following shall hold:112)

  • the left operand has atomic, qualified, or unqualified arithmetic type, and the right has arithmetic type;
  • the left operand has an atomic, qualified, or unqualified version of a structure or union type compatible with the type of the right;
  • the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;
  • the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) one operand is a pointer to an object type, and the other is a pointer to a qualified or unqualified version of void, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;
  • the left operand is an atomic, qualified, or unqualified pointer, and the right is a null pointer constant; or
  • the left operand has type atomic, qualified, or unqualified _Bool, and the right is a pointer.

The two fattened points are the ones relevant here, and none of them is fulfilled without a cast.

Quote from Lundin in the comments:

For example given unsigned* ptr = NULL; ... ptr = 0x12345678; foo = *ptr; might in theory lead to the compiler accessing address NULL. Because during optimization the compiler is free to assume that ptr was never assigned a value, since no valid form of pointer assignment is present in the code.

But there are other cases where casting is used for some trickery. A classic example is the Carmack trick used in the original Doom engine. Here is the code with original comments:

float Q_rsqrt( float number )
{
    long i;
    float x2, y;
    const float threehalfs = 1.5F;

    x2 = number * 0.5F;
    y  = number;
    i  = * ( long * ) &y;                       // evil floating point bit level hacking
    i  = 0x5f3759df - ( i >> 1 );               // what the fuck? 
    y  = * ( float * ) &i;
    y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
//  y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

    return y;
}

NOTE The above code causes undefined behavior, and should NOT be considered an example of good C code.

Also, some people use casting to hush the compiler even when they should not. Remember that hushing the compiler is always a risk. Here is an example of how it can go wrong:

int main()
{
    char c = 'h';
    float a = 0.123;
    printf("%c %f\n", c, a);
    int *cp = (int *) &c;
    *cp = 'h';
    double *ap = (double*) &a;
    *ap = 0.123;
    printf("%c %f\n", c, a);
}

And the output. These two lines "should" be the same.

$ ./a.out 
h 0.123000
? -0.000000

Casting is a very dangerous thing. Always think twice before a cast.

klutt
  • 30,332
  • 17
  • 55
  • 95
  • that comment sums up my understanding of that line – Cantaff0rd Apr 23 '19 at 09:36
  • "The code would compile and work well without the cast" No, it is not defined by the C language what will happen if you don't use a cast. Also, this trashy code you linked invoke UB for other reasons namely strict aliasing, and also impl.defined right shifts of signed integers. It should not be used or studied... the comments speak for themselves. – Lundin Apr 23 '19 at 10:51
  • For example given `unsigned* ptr = NULL; ... ptr = 0x12345678; foo = *ptr;` might in theory lead to the compiler accessing address NULL. Because during optimization the compiler is free to assume that `ptr` was never assigned a value, since no valid form of pointer assignment is present in the code. – Lundin Apr 23 '19 at 10:57
  • @Lundin Thanks. I addressed those issues. – klutt Apr 23 '19 at 13:11
  • Don't quote me, quote the C standard. C17 6.5.16.1. Which in turn only says that this is a constraint violation, so anything might happen. – Lundin Apr 23 '19 at 13:14
  • @Lundin I will add that. But if it is ok with you, I'd like to keep your quote. It explained it pretty good. – klutt Apr 23 '19 at 13:18
  • But the quote is mostly speculation of how UB can manifest itself, which isn't very meaningful. The important part is to know that it _is_ UB. – Lundin Apr 23 '19 at 13:20
  • @Lundin It's your quote, so you get the final word. I can remove the complete quote or just your name if you wish, but I do think that it adds value. – klutt Apr 23 '19 at 13:25
  • At any rate, it is becoming painfully obvious that this is an identical dupe of the post I linked. Would have cast close votes myself, but I'm partial, so... – Lundin Apr 23 '19 at 13:29
  • @Lundin ...so you drop a hint that I cannot ignore? :D Close vote casted. – klutt Apr 23 '19 at 13:37