0

Not sure if I'm phrasing the question properly nor how to best explain what I'm trying to have answered so bear with me.

When defining a microcontroller register, you would write something like this:

#define io_register (*(volatile unsigned char *)0x25)

I also found this line of code here: Pass a hex address to a Pointer Variable

int *pointer = (int *) 0x00010010;

I understand that a pointer that points at an int is being declared left of the = sign, but why is there a typecast *(int ) right of it?

Same with the #define, I understand that the value at 0x25 is being dereferenced but why am I not able to write it like this:

#define io_register *(0x25)

or

int *pointer = 0x25;

What am I missing here? Please feel free to rephrase or correct any mistakes I've made, still trying to wrap my head around pointers and registers.

Tisa
  • 41
  • 8
  • Tell me can you do this:- `float var = "abc";`? – Shubham Jun 24 '20 at 15:24
  • @Lucas it will store in float the reference to string literal. If you cast `float var = (float)"abc";` you will suppress the warning. – 0___________ Jun 24 '20 at 15:50
  • My beloved brother @P__J__ , after writing this expression into my code, i'll not get the **`warning`**, i'll get an error stating that `error: incompatible types when initializing type 'float' with type 'char *'`. – Shubham Jun 25 '20 at 01:35
  • @P__J__ Even if I typecast the string literal. After typecasting we'll get `error: pointer value used where a floating point value was expected` So, tell me what are you talking about _"it will store in float the reference to string literal."_? – Shubham Jun 25 '20 at 01:37
  • As for microcontroller registers specifically, in order to access such a register portably, you have to cast an absolute address to a pointer and then de-reference it, because that's the only mechanism C offers to access a specific address. Embedded system compilers often provide non-standard options to declare a variable at an absolute address, like @ or #pragma, but those aren't standard nor portable. – Lundin Jun 25 '20 at 06:20
  • "_... why is there a typecast *(int ) right of it?_" - there isn't; you cannot deference an `int` and the cast is `(int*)` in any case which is entirely different. – Clifford Jun 25 '20 at 07:51

4 Answers4

2

An important prerequisite of any assignment operation is data type compatibility. In other words, the data type of the equation's (int *pointer = 0x25;) LHS (int *pointer) must be compatible with whatever data type results from the evaluation of the equation's RHS (0x25).

For example, if both LHS and RHS are int types, then there will be no problem assigning the integer value of RHS to LHS.

But, in this expression:

int *pointer = 0x25;

you have int * data type in LHS and int data type in RHS. So, there's an incompatibility between LHS & RHS. That's why you need to cast RHS to (int *).

Shubham
  • 1,153
  • 8
  • 20
  • Must not. Should be. And compiler will ask (using warning): `dude! Are you sure?`. When you explicitly cast you answer `Yes I am, my compiler friend` – 0___________ Jun 24 '20 at 15:52
  • I'm sorry. I didn't get you. @P__J__ – Shubham Jun 25 '20 at 01:06
  • If you're about this exp. `int *pointer = 0x25`. then you know, everyone is aware that we can't provide a memory address to the pointer manually. – Shubham Jun 25 '20 at 01:08
  • 1
    @P__J__ This answer is correct. The compiler may as well give an error as a warning, as long as it gives some manner of diagnostic. The reason for this isn't "are you sure", but "this is invalid C, would you like a non-standard extension?" For details see this: https://stackoverflow.com/questions/52186834/pointer-from-integer-integer-from-pointer-without-a-cast-issues – Lundin Jun 25 '20 at 06:15
1

The cast is needed because 0x00010010 is not a pointer but an integer (it is the first type among int, unsigned int or long int that can represent the value 65552) .

Only integer constant expressions having value of 0 can be converted to a pointer implicitly (i.e. without a cast); the resulting pointer would be a null pointer.


You can naturally write

#define io_register *(0x25)

but you cannot use that io_register to access memory at address 0x25, because that 0x25 is not a pointer - it is an integer.

In C one does not really access addresses; instead one dereferences pointers to get lvalues that designate an object, and then get the value of that object, or a set a new value to it.

1

With

int *pointer = (int *) 0x00010010;

You are telling the pointer to point to an absolute address in memory, the value at that address can be dereferenced with *pointer.

With

int *pointer = 0x25;

The compiler does not like that because 0x25 is an integer but pointer is not an integer, it is an integer pointer.

AndersK
  • 35,813
  • 6
  • 60
  • 86
1

The cast suppresses the warning. That is its role in those statements. Otherwise it will be casted implicit way, and warning omitted. No difference in the code or program execution.


#define io_register *(0x25)

*(0x25) will not be a pointer in any circumstanes and io_register when used means : multiply by 0x25.

int x = 10 io_register;

which means: int x = 10 *(0x25);

0___________
  • 60,014
  • 4
  • 34
  • 74
  • Just to clarify something, 0x25 can be written as a int value in C? I.e. binary hex etc? And can I perform bitshifting and such on ints containing a hexadecimal or binary value? – Tisa Jun 24 '20 at 17:56
  • 0x25 it is integer constant and it is an integer value. the is no diferenece between 16, 0x10, 020 0b10000 (0b is a gcc extension). – 0___________ Jun 24 '20 at 18:02
  • Yeah, just tried shifting some 0b value and printing them as %d so I get what you mean. Thanks for the help! – Tisa Jun 24 '20 at 18:06
  • "Otherwise it will be casted implicit way" This is incorrect. First, a cast is always explicit, you mean conversion. Second, if you don't cast, the code is invalid C since it doesn't sate the constraints of simple assignment. – Lundin Jun 25 '20 at 06:14
  • 1
    `int * pointer = 0x25;` is invalid C, it's a constraint violation. A compiler must produce a diagnostic message. Nothing "implicit" should happen, that's non-conforming/non-standard extensions. – Lundin Jun 25 '20 at 07:43
  • @Lundin it is a constraint violation - but the code is still valid. I do not know any compiler which emits the error here. Tested today iar. keil, green hills – 0___________ Jun 25 '20 at 07:57
  • 1
    That's just the usual issue of warnings vs errors and what should block the code from producing a binary - such things are beyond the scope of the C language. Popular compilers like gcc and clang blocks invalid C from compiling if you use `-pedantic-errors`. If you don't, they will just give a warning and produce a non-conforming binary. If you just compile with the default, such as gnu11, then gnu11 is what you get, not c11. – Lundin Jun 25 '20 at 08:54
  • 1
    Embedded system compilers are likely more lenient, though just for the record I found one which doesn't allow it. Codewarrior gives "error: type mismatch (expected int*, given int)". This is fully conforming behavior. – Lundin Jun 25 '20 at 08:57