0

I have read what I could find on pointers in C/C++ but most of it is introductory, and while it helps you to understand using them there are many cases where existing code throws examples that are troublesome to decipher.

I did see some examples where they break down a line of code into what it really means and some of the more complex ones end up with something like: "a pointer to a function that returns a pointer to a pointer of an int"

Ok great, but what kind of scenario would you run into where you would end up with this? Is this sort of pointer situation something that comes up often? It does not seem very readable and if you had code full of this I could see a great possibility of bugs popping up.

I have found one line of code in a library that I do not fully understand but it is not quite the crazy deciphered example listed above: *(uint8_t *)&(SPI2->DR) = SPI2_DATA;

SPI2_DATA is getting assigned to the DR of SPI2, but what is all that other code for?

As far as I can tell the code is doing a bitwise AND between a pointer to a uint8_t and the DR of SPI2 and then dereferencing the whole thing to assign SPI2_DATA to it. I know that is not right though?

Darren
  • 97
  • 5
  • 2
    & is also to get the address of a variable anyway to ask for books/tutorials/external resources is now off-topic for SO (but there are few old answers with pretty good lists). – Adriano Repetti Sep 12 '14 at 16:10
  • The `&` in the assignment is the unary address-of operator. It takes the address of `SPI2->DR`, treats it as a pointer to a `uint8_t` and then dereferences it (assigning `SPI2_DATA` to the 8-bit integer...). – Jonathan Leffler Sep 12 '14 at 16:12
  • See [Understanding typedefs for function pointers in C](http://stackoverflow.com/questions/1591361/understanding-typedefs-for-function-pointers-in-c-examples-hints-and-tips-ple/) for one source of information. – Jonathan Leffler Sep 12 '14 at 16:16
  • 1
    "& is also" <- Ah, that is right, I was looking at bitwise operations for the last while and my mind defaulted to "bitwise and" but yes it is to get the address when dealing with pointers, I should have caught this – Darren Sep 12 '14 at 16:26

3 Answers3

3

You should decompose the instruction to fully understand what happens:

*(uint8_t *)&(SPI2->DR) = SPI2_DATA

&SPI->DR obtains the address of the variable DR in struct/class SPI, this address has type Something* where Something is the type of DR.

Then this address is casted to uint8_t*, so it is casted to a pointer to a uint8_t, which is a fixed width unsigned integer of 1 byte.

Finally this address is dereferenced to assign SPI2_DATA to it.

Something like:

Something* temp1 = &SPI2->DR;
uint8_t* temp2 = (uint8_t*)temp1;
*temp2 = SPI2_DATA;
Jack
  • 131,802
  • 30
  • 241
  • 343
  • __IO uint16_t DR; So Something* would be unit16_t* temp1 in above? – Darren Sep 12 '14 at 16:43
  • As a side note, if `SPI2->DR` is of type `Something` and that `Something` isn't a `int8_t` or `uint8_t`, that's a violation of strict aliasing. – mafso Sep 12 '14 at 17:46
1

Here's an example of what it does:

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>

    #define SPI2_DATA       0xfc

    struct spi {
            uint16_t DR;
    };

    int main ( void ) {

            struct spi *    SPI2 = malloc(sizeof(*SPI2));

            SPI2->DR = 0x3210;          /* some initial value chosen on a whim */

            printf("before: %04x\n", SPI2->DR);

            *(uint8_t *)&(SPI2->DR) = SPI2_DATA;

            printf(" after: %04x\n", SPI2->DR);

            return 0;
    }


before: 3210
 after: 32fc

Note how only 8 bits of the value changed.

John Hascall
  • 9,176
  • 6
  • 48
  • 72
  • Is it correct that the reason this is done is because the SPI interface only sends 1 byte at a time so only the first 8 bits of the 16 bit DR are sent in this case? I guess have to dig into the datasheet to see how the SPI interface on this chip works specifically with the 16 bit data register – Darren Sep 12 '14 at 17:15
  • @Darren -- exactly -- I'm not familiar with whatever the SPI is, but certainly with some devices you need to be very careful which parts of a register you read and/or write because it might trigger a different behavior then you wanted. – John Hascall Sep 12 '14 at 17:18
0

SPI2->DR is probably declared as a pointer, but not a pointer to the type uint8_t (maybe it's declared as a pointer to void). SPI2_DATA is of type uint8_t. So in order to copy SPI2_DATA into the target of SPI2->DR, the code is getting the pointer using &, converting the pointer to the correct type with a cast, then dereferencing it.

JoelFan
  • 37,465
  • 35
  • 132
  • 205