Thread: Manipulate the pointers pointing to address

  1. #1
    Registered User
    Join Date
    Apr 2015
    Posts
    6

    Manipulate the pointers pointing to address

    Hi!

    I'm having trouble with the concepts of pointers. I have attached a picture to illustrate what I try to explain. I have tried to read several guides/tutorials about pointers without any luck. Probably because I don't know how to express my self.

    I'm playing with a PIC-processor

    Question:
    See the code below


    Code:
    int varA = 10;
    int varB = 20;
    int temp_addr = 0;
    
    int *handle;
    
    handle = &varA;
    
    temp_addr = (int)&handle;
    printf("%p", temp_addr);
    
    temp_addr ^= 0x0004;
    
    handle = temp_addr; // This does not work but for me it symbols what I want to do..

    For example, lets say that varA is located at memory position 0x0500 and that I know that varB is located at memory position 0x0504. I want a pointer that can swap between the two positions 0x0500 and 0x0504 (or two arbitrarly memory positions). How can I do this?

    In the picture I want the lower box address to change from 0x0500 to 0x0504

    Best regards
    /R
    Attached Images Attached Images Manipulate the pointers pointing to address-pointers-png 

  2. #2
    Registered User
    Join Date
    May 2010
    Posts
    4,547
    Let's start with a complete program.
    Code:
    #include <stdio.h>
    
    int main(void)
    {
       int varA = 10;
       int varB = 20;
       int temp_addr = 0;
    
       int *handle;
    
       handle = &varA;
    
       temp_addr = (int)&handle;
       printf("%p", temp_addr);
    
       temp_addr ^= 0x0004;
    
       handle = temp_addr; // This does not work but for me it symbols what I want to do..
    
       return 0;
    }
    Now let's look at the errors and warnings being generated by my compiler for your code:

    main.c||In function ‘main’:|
    main.c|13|warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]|
    main.c|14|warning: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘int’ [-Wformat=]|
    main.c|18|error: assignment makes pointer from integer without a cast|
    main.c|6|warning: unused variable ‘varB’ [-Wunused-variable]|
    ||=== Build finished: 1 errors, 3 warnings (0 minutes, 0 seconds) ===|
    The first warning is line 13:
    Code:
      temp_addr = (int)&handle;
    Here temp_addr is not a pointer, but you're trying to cast a pointer to a pointer to an int into this non-pointer. What exactly are you trying do in this line?

    Now the second warning, this is line 14, your printf()
    Code:
       printf("%p", temp_addr);
    You appear to be trying to print the address of this variable but instead of the address you're passing the value being held in that variable. You need to pass the address, using the ampersand, and you'll need to cast that pointer to the required type (void*).
    Code:
       printf("%p", (void*)&temp_addr);
    You already know about the error, it is being caused because handle is a pointer and temp_addr is an int. If you want to assign the value being held in temp_addr to handle you need to de-reference the pointer (*handle = temp_addr. If you want handle to point to temp_addr you need to use the ampersand (handle = &temp_addr.

    Jim

  3. #3
    Registered User
    Join Date
    Apr 2015
    Posts
    6
    I'm sorry I wanted to try to simplify the real code with an example but probably confused both you and me. Here is the real code

    It is a part of the PIC USB framework (Microchips' own).
    The unions have been simplified and I know I miss a main.

    Code:
    typedef union _BD_STAT
    {
        struct{
            unsigned BC8:1;
            unsigned BC9:1;
            unsigned BSTALL:1;
            unsigned DTSEN:1;
            unsigned INCDIS:1;
            unsigned KEN:1;
            unsigned DTS:1;
            unsigned UOWN:1;
        };
    } BD_STAT;
    
    typedef union __BDT
    {
        struct
        {
            BD_STAT STAT;
            uint8_t CNT;
            uint8_t ADRL;
            uint8_t ADRH;
        };
    } BDT_ENTRY;
    
    typedef union
    {
        uint8_t Val;
    } uint8_t_VAL
    
    volatile BDT_ENTRY BDT[8] @0x0400;    // Line A
    volatile BDT_ENTRY *pBDTEntryIn[2];    // Line B
    
    pBDTEntryIn[0] = (volatile BDT_ENTRY*)&BDT[2];     // Line C
    
    ((uint8_t_VAL*)&pBDTEntryIn[0])->Val ^= 0x0004;    // Line D
    Here is how I understand it.. Line A defines an array of 8 BDT elements, each element is 4 bytes and it starts at memory address 0x0400 and ends at address 0x0420.

    Line B defines an array of BDT_ENTRY pointers

    Line C assigns the address of BDT[2] (which should be 0x0408, right?!) to pBDTEntryIn[0].
    Question 1: Couldn't the (volatile BDT_ENTRY*) be omitted? What's the use of it?

    Line D this is where I fail to understand.. In my understanding pBDTEntryIn[0] points at the address 0x0408, and what Line D does is that it XOR's 0x0408 with 0x0004 giving 0x040C. This address is now what pBDTEntryIn[0] points at.
    Question 2: I guess Line D can be written in a less compact way, and that was what I was trying to describe in #1
    Question 3: Is there a way to do this without the uint8_t_VAL structure?

  4. #4
    Registered User
    Join Date
    May 2010
    Posts
    4,547
    What compiler are you using?

    You seem to be getting confused by all the casting going on. And since you're using some non-standard items I can only guess as to what is happening.

    Line A does appear to be creating an array of BDT starting at 0x0400. By the way the @0x0400 is non-standard.

    Line B you appear to be correct.

    Line C does appear to assign the address of BDT[2] to pBDTEntryIn[0]. And no the (volatile BDT_ENTRY*) can not be omitted, this is casting the address of BDT[2] to a BDT_ENTRY pointer.

    Line D the first part (unit8_t_VAL*) is casting the address of BDTEntryIn[0] to a uint8_t_VAL*, and then modifying the value that is held in the member variable, Val.

    Jim

  5. #5
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by redsmolf View Post
    Question 1: Couldn't the (volatile BDT_ENTRY*) be omitted?
    volatile tells the compiler that the value may change at any time, and it should not make any assumptions about it.

    volatile TYPE *pointer; means that the value the pointer points to may change.
    TYPE *volatile pointer; on the other hand means that the pointer itself may change.
    volatile TYPE *volatile pointer; means both the pointer, and the value it points to, may change at any time.

    Just read the specifiers from right to left, delimited by the asterisks, and you'll get it right. For example,
    const volatile TYPE *const ptr = foo; declares pointer ptr whose value will not change. The data it points to is read-only, and may change at any time.

    At line C, pBDTEntryIn[0] = (volatile BDT_ENTRY*)&BDT[2]; , the cast is not needed, as the type of pBDTEntryIn[0] and &BDT[2] is the same, (volatile BDT_ENTRY *). However, it does no harm, and is useful to us programmers to remind us that we're dealing with pointers that point to volatile stuff, and need to be careful.

    Quote Originally Posted by redsmolf View Post
    Question 2: I guess Line D can be written in a less compact way, and that was what I was trying to describe in #1
    Question 3: Is there a way to do this without the uint8_t_VAL structure?
    Sure, as long as you have an integer type sufficient to hold a pointer.

    Many compilers provide intptr_t in stdint.h header file. If we have it available, this will work:
    Code:
    pBDTEntryIn[0] = (volatile BDT_ENTRY *)( (intptr_t)pBDTEntryIn[0] ^ sizeof (BDT_ENTRY *) );
    We convert the pointer to an integer, do the exclusive-OR operation (using the size of the pointer, in case it happens to be other than 4), and finally cast back to a pointer.

    It does have the downside that it is a read-modify-write operation, so if you happen to have an interrupt or something at the same time, the code the compiler generates might leave it in a bad state.

    GCC and other C compilers provide atomic built-ins that would help here. XC8, I am not sure about. However, on many microcontrollers and C compilers,
    Code:
    *(intptr_t *)(&pBDTEntryIn[0]) ^= sizeof (BDT_Entry *);
    results in an atomic operation that achieves the same thing. We cheat a little, by treating the pointer value directly as an intptr_t (by casting the address of the variable holding the pointer value to an intptr_t pointer, and modifying the target directly).

    You seem to be using a 32-bit microcontroller which uses the IP32 model (ints and pointers are both 32-bit), in which case you can define the type yourself if your header files do not provide them for you:
    Code:
    typedef int  intptr_t;
    typedef unsigned int  uintptr_t;
    But remember: never do the above yourself, if you can obtain them from a standard header file. Makes life much easier in the long run.

  6. #6
    Registered User
    Join Date
    Apr 2015
    Posts
    6
    Thanks for the answer!

    Quote Originally Posted by Nominal Animal View Post
    Many compilers provide intptr_t in stdint.h header file. If we have it available, this will work:
    Code:
    pBDTEntryIn[0] = (volatile BDT_ENTRY *)( (intptr_t)pBDTEntryIn[0] ^ sizeof (BDT_ENTRY *) );
    We convert the pointer to an integer, do the exclusive-OR operation (using the size of the pointer, in case it happens to be other than 4), and finally cast back to a pointer.
    Is it really the size of the pointer that should be used and not sizeof(BDT_ENTRY) or is it the same?

    And yes I use XC8 as a compiler.

    Quote Originally Posted by Nominal Animal View Post
    You seem to be using a 32-bit microcontroller which uses the IP32 model (ints and pointers are both 32-bit), in which case you can define the type yourself if your header files do not provide them for you:
    Code:
    typedef int  intptr_t;
    typedef unsigned int  uintptr_t;
    No it's actually a PIC18F4550 (8-bit) so that is also a question, why they use an 8-bit structure (uint8_t_VAL) when modifying a 16-bit address. The result is the same since you only want to change the lowest part of the address, or?

  7. #7
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by redsmolf View Post
    Is it really the size of the pointer that should be used and not sizeof(BDT_ENTRY) or is it the same?
    Good point! Hmm.. pBDTEntryIn[0] is a pointer, initialized to point to the third entry of BDT. Using sizeof (BDT_ENTRY) instead of sizeof (BDT_ENTRY *) would mean the intent is to have it flip between pointing to the third and fourth entries in BDT, i.e. between pointing to BDT[2] and BDT[3].

    Assuming that is the intent, then yes, you'd certainly want to use sizeof (BDT_ENTRY) instead. It's very nice to see you're keeping a sharp eye!

    However, to flip between two values, you exclusive-or the value by a constant that is the result of exclusive-or'ing the two addresses. This means that the correct forms would actually be
    Code:
    pBDTEntryIn[0] = (volatile BDT_ENTRY *)( (intptr_t)pBDTEntryIn[0] ^ (intptr_t)&BDT[2] ^ (intptr_t)&BDT[3] );
    and
    Code:
    *(intptr_t *)(&pBDTEntryIn[0]) ^= (intptr_t)&BDT[2] ^ (intptr_t)&BDT[3];
    respectively.

    Quote Originally Posted by redsmolf View Post
    No it's actually a PIC18F4550 (8-bit) so that is also a question, why they use an 8-bit structure (uint8_t_VAL) when modifying a 16-bit address. The result is the same since you only want to change the lowest part of the address, or?
    Ah, the microcontroller itself is 8-bit, but the C environment has IP32. It is a little-endian architecture, right?

    Since we already know that the array starts at an address with low 8 bits zero (0x400, two rightmost digits 0), and we know the BDT entries are less than 64 bytes long, we know that only the eight low bits can change in the flipping. Therefore, we can do
    Code:
    *(unsigned char *)(&pBDTEntryIn[0]) ^= (unsigned char)( (intptr_t)(&BDT[2]) ^ (intptr_t)(&BDT[3]) );
    if the microcontroller is little-endian (stores values least significant byte first).

    If the microcontroller was big-endian, or pdp-endian, the least significant byte of the address the pointer points to would not be at that address, and we'd probably have to use something like ((unsigned char *)(&pBDTEntryIn[0]))[1] ^= (unsigned char)( (intptr_t)(&BDT[2]) ^ (intptr_t)(&BDT[3]) );

    In any case, the right side evaluates to a compile-time constant; the operands are only the addresses for the BDT array elements.

    The final question is, why did Microchip write the expression using that union in the first place? It might be a quirk in XC8, perhaps something known to Microchip employees, mentioned in internal-only documentation, that if you use such a typedef'd union and that kind of expression, the compiler will always compile it using an atomic mnemonic?

    You could check, I guess, by compiling a test function using either approach in separate files, and check if the object code produced by XC8 is the same in both cases. Even if they are, there could be some kind of historical or future reason they're using that form -- perhaps they intend to provide the guarantee, or a previous version of the compiler had a bug they fixed in the library rather than in the compiler?

    Or maybe the programmer who wrote that was just hoping for job security? Lock-in is not limited to companies, some people do it, too.
    (Or had a bad day/week/month/year, or wasn't a particularly good programmer to start with.)

    This is why I don't like closed tools: magic info known only to privileged individuals.

  8. #8
    Registered User
    Join Date
    Apr 2015
    Posts
    6
    Quote Originally Posted by Nominal Animal View Post
    Good point! Hmm.. pBDTEntryIn[0] is a pointer, initialized to point to the third entry of BDT. Using sizeof (BDT_ENTRY) instead of sizeof (BDT_ENTRY *) would mean the intent is to have it flip between pointing to the third and fourth entries in BDT, i.e. between pointing to BDT[2] and BDT[3].

    Assuming that is the intent, then yes, you'd certainly want to use sizeof (BDT_ENTRY) instead. It's very nice to see you're keeping a sharp eye!

    However, to flip between two values, you exclusive-or the value by a constant that is the result of exclusive-or'ing the two addresses. This means that the correct forms would actually be
    Code:
    pBDTEntryIn[0] = (volatile BDT_ENTRY *)( (intptr_t)pBDTEntryIn[0] ^ (intptr_t)&BDT[2] ^ (intptr_t)&BDT[3] );
    and
    Code:
    *(intptr_t *)(&pBDTEntryIn[0]) ^= (intptr_t)&BDT[2] ^ (intptr_t)&BDT[3];
    respectively.


    Ah, the microcontroller itself is 8-bit, but the C environment has IP32. It is a little-endian architecture, right?

    Since we already know that the array starts at an address with low 8 bits zero (0x400, two rightmost digits 0), and we know the BDT entries are less than 64 bytes long, we know that only the eight low bits can change in the flipping. Therefore, we can do
    Code:
    *(unsigned char *)(&pBDTEntryIn[0]) ^= (unsigned char)( (intptr_t)(&BDT[2]) ^ (intptr_t)(&BDT[3]) );
    if the microcontroller is little-endian (stores values least significant byte first).

    If the microcontroller was big-endian, or pdp-endian, the least significant byte of the address the pointer points to would not be at that address, and we'd probably have to use something like ((unsigned char *)(&pBDTEntryIn[0]))[1] ^= (unsigned char)( (intptr_t)(&BDT[2]) ^ (intptr_t)(&BDT[3]) );

    In any case, the right side evaluates to a compile-time constant; the operands are only the addresses for the BDT array elements.

    The final question is, why did Microchip write the expression using that union in the first place? It might be a quirk in XC8, perhaps something known to Microchip employees, mentioned in internal-only documentation, that if you use such a typedef'd union and that kind of expression, the compiler will always compile it using an atomic mnemonic?

    You could check, I guess, by compiling a test function using either approach in separate files, and check if the object code produced by XC8 is the same in both cases. Even if they are, there could be some kind of historical or future reason they're using that form -- perhaps they intend to provide the guarantee, or a previous version of the compiler had a bug they fixed in the library rather than in the compiler?

    Or maybe the programmer who wrote that was just hoping for job security? Lock-in is not limited to companies, some people do it, too.
    (Or had a bad day/week/month/year, or wasn't a particularly good programmer to start with.)

    This is why I don't like closed tools: magic info known only to privileged individuals.
    Thanks for the answer!
    And yes I think the intent is to flip between two BDT entries.
    Great answers!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 7
    Last Post: 02-28-2012, 07:29 PM
  2. Printf error "address pointing at code space is taken"
    By KMAN999 in forum C Programming
    Replies: 2
    Last Post: 07-04-2011, 03:27 PM
  3. Finding address pointing to a value
    By 843 in forum C++ Programming
    Replies: 4
    Last Post: 04-07-2011, 11:44 AM
  4. Replies: 6
    Last Post: 10-08-2008, 05:51 AM
  5. Pointing to a Queue of Pointers?
    By Dragoon_42 in forum C++ Programming
    Replies: 2
    Last Post: 04-08-2004, 09:19 PM