This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Issue with pointer math in CCS4 microcontroller edition

Other Parts Discussed in Thread: MSP430F2618

Hello,

I am working with CCS V4.0.0.16000, developing for a MSP430F2618 (X architecture) microcontroller in C and I have run into an issue with pointer math calculations generated by the compiler for what I would think should only need simple arithmetic calculations.

For this line of code:

pxLink->pxNextBlock = pxLink + pxLink->uiBlockLength;

The compiler generates the following dissassembly:

26               pxLink->pxNextBlock = pxLink + pxLink->uiBlockLength;
0x0316a:   422F                MOV.W   #4,R15
0x0316c:   1800 515F 0004      ADDX.A  0x00004(SP),R15
0x03172:   4F2C                MOV.W   @R15,R12
0x03174:   430D                CLR.W   R13
0x03176:   403E 0006           MOV.W   #0x0006,R14
0x0317a:   430F                CLR.W   R15
0x0317c:   13B0 331A           CALLA   #__mpyl_hw
0x03180:   013E 0004           MOVA    0x0004(SP),R14
0x03184:   4D0F                MOV.W   R13,R15
0x03186:   0E4F                RLAM.A  #4,R15
0x03188:   0E4F                RLAM.A  #4,R15
0x0318a:   0E4F                RLAM.A  #4,R15
0x0318c:   0E4F                RLAM.A  #4,R15
0x0318e:   1800 DC4F           BISX.A  R12,R15
0x03192:   0FEE                ADDA    R15,R14
0x03194:   013F 0004           MOVA    0x0004(SP),R15
0x03198:   0E7F 0000           MOVA    R14,0x0000(R15)

The assembly always produces the wrong results for the "pxLink + pxLink->uiBlockLength" part of the code which messes up everything else. Functionally the assembly multiplies the pxLink->uiBlockLength by the length of the pxLink struct. I don't understand why it would use the hardware multiplier under these circumstances at all though.

Just for some context, this code is coming out of a memory management routine that uses a linked list header in each block subdividing the heap. I have uploaded some code that exhibits this issue here. You can also take a look on pastebin: http://pastebin.com/m16b19f8a

I appreciate any help or insight into what might be causing this issue.

-Aaron

  • C math operations on pointers treat the pointers with the knowledge of what they are pointing to. If you wrote

    pxLink += 1;

    then the compiler would increment pxLink by 1 struct size so it will be pointing to the next struct. And this method should always work for accurately reaching the next struct in an array.

    Adding whatever uiBlockLength represents will result in multiplying the space taken up by the struct (usually the size of the struct) by the addend uiBlockLength. It is possible on some devices and some struct configurations for an alignment hole to be left between adjacent structs; this means that sizeof(struct-type) might not be the same as the distance between adjacent structs.

    The += 1 may be what you need to do for your case, but that is just making assumptions on my part about your application.

  • RandyP, your answer helped explain what the compiler was generating and I think I have developed a work around.

    The pxLink pointers aren't referencing elements in an array, but rather elements in a linked list. Each list element is a header to a memory block of a variable size used to manage and segment the heap so when I increment the pointer it needs to be by the size of the structure + the size of its associated memory block. It looks like I can cast pxLink as a size_t and then add pxLink->uiBlockSize and then recast the result as a xBlockLink pointer. This eliminates the multiplication step and gives the correct address of the next block in memory.

    Thanks again for your help.

  • The canonical way to do this sort of thing is to cast the pointer to a "char *" before the arithmetic.  Using size_t will work in this case, but isn't strictly speaking portable.  The cast to "char *" is portable.

  • Thanks for pointing that out. Either way the variable type will be determined by the compiler but at least "char *" makes it more explicit and readable.