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 dereferencing an array of pointers

Other Parts Discussed in Thread: MSP430F2618

I've run into an issue working with arrays of pointers where writing values to the pointer array elements seems to work fine (the correct addresses are assigned in memory and are 32-bit aligned since I am using the large data model for a MSP430F2618) but the dereferenced array values appear to be read back by the IDE and later code as 24-bit aligned values. This doesn't really make sense to me but here is some toy code to illustrate the issue:

#define    STRUCT_LIST_SIZE    4

typedef struct SOME_STRUCT
{
    char    cParam1;
    char    cParam2;
    int        iParam3;
}xSomeStruct;
typedef xSomeStruct * pxSomeHandle;
static pxSomeHandle pxStructHandleList[ STRUCT_LIST_SIZE ];

int main( void )
{
    xSomeStruct    xStructA, xStructB, xStructC, xStructD;
    int i;

    for( i = 0; i < STRUCT_LIST_SIZE; i++ )
    {
        pxStructHandleList[i] = 0x0000;
    }
    pxStructHandleList[0] = &xStructA;
    pxStructHandleList[1] = &xStructB;
    pxStructHandleList[2] = &xStructC;
    pxStructHandleList[3] = &xStructD;
    return 0;
}

Here is what the memory view shows me after all of the array elements have been assigned:

0x001100  .bss, _bss, pxStructHandleList

0x001100  30EA  0000  30EE  0000  30F2  0000  30F6  0000

Which matches my expectations but when I look at pxStructHandleList in the Watch window I see this:

pxStructHandleList    0x001100

    [0]   0x0030EA

    [1]   0x30EE00

    [2]   0xF20000

    [3]   0x000030

When I try to access the structures using the pointer array (pxStructHandleList[i]->cParam1) it looks like it uses the addresses as represented in the watch window (half of which are invalid) and things just break down from there. Does anyone have some insight into what is going on? Thanks in advance!

BTW I am using CCS V4.0.0.16000 microcontroller edition and working with a MSP430F2618.

  • I've done a bit more poking around with this issue and I think there is a discontinuity in the way the CCS compiler treats pointers. When the compiler allocates RAM to hold the array of pointers it sets aside 4 bytes for each element (as it should), however when it calculates the array index it does so in increments of 3, not 4, almost as if it forgot the byte alignment.

    To illustrate my point, if I define a union type:

    typedef union u_pointer
    {
        pxSomeStruct    *pxHandleUnion;
    }uPointer;

    and then create an array:

    static uPointer pxUnionList[ STRUCT_LIST_SIZE ];

    The compiler knows that the smallest memory block that will contain the pointer is 4 bytes so the sizeof( uPointer ) is 4 and when I reference elements in the array it increments the array index by 4 bytes and I can correctly access the stored values.

    The question is then, why does the compiler treat pointers as 4-bytes when allocating memory for them, but then 3-bytes when calculating array index values? Is this a bug in the TI compiler? Is there a setting that tells the compiler what size to treat pointers as?

  • Here is code to illustrate the point:

    #define    STRUCT_LIST_SIZE    4

    typedef struct SOME_STRUCT
    {
        char    cParam1;
        char    cParam2;
        int        iParam3;
    }xSomeStruct;

    typedef xSomeStruct * pxSomeHandle;

    typedef union u_pointer
    {
        pxSomeHandle    pxHandleUnion;
    //    long            lUnionValue;
    //    int                iUnionValue;
    }uPointer;

    //static pxSomeHandle pxStructHandleList[ STRUCT_LIST_SIZE ];

    static volatile uPointer pxUnionList[ STRUCT_LIST_SIZE ];

    static volatile pxSomeHandle pxStructHandleList[ STRUCT_LIST_SIZE ];

    int main( void )
    {
        xSomeStruct    xStructA, xStructB, xStructC, xStructD;
        int i;
       
        for( i = 0; i < STRUCT_LIST_SIZE; i++ )
        {
            pxUnionList[i].pxHandleUnion = 0x0000;
            pxStructHandleList[i] = 0x0000;
        }
       
        pxUnionList[0].pxHandleUnion = &xStructA;
        pxUnionList[1].pxHandleUnion = &xStructB;
        pxUnionList[2].pxHandleUnion = &xStructC;
        pxUnionList[3].pxHandleUnion = &xStructD;
         
        pxStructHandleList[0] = &xStructA;
        pxStructHandleList[1] = &xStructB;
        pxStructHandleList[2] = &xStructC;
        pxStructHandleList[3] = &xStructD;
       
        return 0;
    }

    The pxUnionList will be correctly referenced when reading back the values whereas the pxStructHandleList will be wrong.

  • Is this pointer size calculation issue a potential compiler bug? Somebody please help!

  • Aaron, I think you're in the wrong forum here, try the CCS one.

    I wasn't aware that CCS did a compiler for CC430, they specialize in PICs. I have been using their PIC compliler for a while and it has had pointer issues in the past. I wouldn't start a new project with CCS now, it has far too many updates ; there never seems to be a stable release.

    Sorry this wasn't the answer you were after!

     

     

  • Sorry, you are mixing something up here, this is about TI CCS (Code Composer Studio), which only supports TI and affiliates microcontrollers. It has nothing to do with the CCS, Inc. Compiler.

     

    To the issue:

    I think the problem you are encountering here is that pointers are treated as 20Bit in the large data memory model, and so only require 3 Bytes in memory, not sure about the alignment. You are defining pxStructHandleList as pxSomeHandle, which is dereferenced the address of xSomeStruct, which is only 20Bit.

    Try defining pxStructHandleList as just an array of *xSomeStruct (struct pointers). Maybe your typedef:

    typedef xSomeStruct * pxSomeHandle;

    was meant to be:

    typedef *xSomeStruct pxSomeHandle;

    ?

    The unions probably work, because unions are aligned in memory, I guess, as the type inside is (at first) considered unknown.

     

    Then I would also try to do all closer investigations with the Memory View, as the Watch Window could get confused at more complex type definitions.

     

    I hope this can help!

  • Dennis,

    Thanks for the reply.  The problem so far as I understand it stems from a discontinuity between how arrays of pointers are stored in memory, and how individual array elements are then read back out.  When the compiler allocates pxStructHandleList[ ] in memory it recognizes that the fewest number of bytes that will contain an array element is 3 bytes, but then adds a 4th byte to maintain byte alignment.  This is very obvious looking at the memory view, as I said in my first post.  When the values are written to memory, the CPU increments the address offset from pxStructHandleList by 4 for each successive write operation in the assembly code in order to accommodate the 4-byte wide containers allocated for each array element. However, when we read data back out, using either the Watch Window or accessing the element directly (i.e. xStructX = pxStructHandleList[2]), it seems the compiler uses it's knowledge of the size of the pointer (20-bits, or 3-bytes) to increment the address offset, essentially forgetting about byte alignment, and it ends up returning an erroneous value.

    Using my previously posted code as an example:

    In the memory view, after assigning values to all of the array elements in pxStructHandleList[ ] we see:

    pxStructHandleList

    30EA 0000 30EE 000 30F2 0000 30F6 0000

    which is identical to what we see in pxUnionList. Let me make that point again: both pxStructHandleList and pxUnionList appear identical in memory! This tells me that when writing to an array of pointers the compiler knows to use a 4-byte container for each array element and behaves accordingly. However when you try to read out the values from the array the compiler uses a 3-byte element size and we get the following jumbled mess:

    pxStructHandleList[0] = 0x0030EA

    pxStructHandleList[1] = 0x30EE00

    pxStructHandleList[2] = 0xF20000

    pxStructHandleList[3] = 0x000030

    What I cannot explain to myself, and what really makes no sense to me is why when writing to the array elements in memory the compiler clearly maintains byte alignment, incrementing the address offset by 4 bytes, but when reading the pointers back from memory it increases the address offset by 3 byte increments. Can someone please explain why this is happening?!

    As far as your reccomendation goes, I don't think typedef *xSomeStruct pxSomeHandle; is valid type definition syntax. Perhaps you can explain what you mean here? I have tried defining pxStructHandleList as

    xSomeStruct * pxStructHandleList[ STRUCT_LIST_SIZE ];

    with no change in the outcome.

    You are correct about the use of unions. The compiler knows that the size of this particular union is 4 bytes (since that is the smallest byte aligned space that will hold the pointer) and so when we read back values from the array of unions we are indexing by the size of the union (4 bytes) rather than the size of the pointer (3 bytes).

  • These examples do not show any C statements reading the values back from memory; there are only assignments.  When I add some code to do reads, they work just fine.  I'm guessing that the problems are all observed while using debug features within CCS, in particular the CCS watch window.  If this is not the case, please post an example that reads the values back and gets an incorrect result.  To demonstrate that the compiler gets this right, the following program works just fine with options "-vmspx -ml":

    #define SIZE 4
    
    struct S
    {
        char    cParam1;
        char    cParam2;
        int     iParam3;
    };
    
    struct S data[4] = { { 0x11, 0x55, 0x9999 },
                         { 0x22, 0x66, 0xaaaa },
                         { 0x33, 0x77, 0xbbbb },
                         { 0x44, 0x88, 0xcccc } };
       
    struct S * ptrs[SIZE];
    
    void set(void)
    {
        ptrs[0] = &data[0];
        ptrs[1] = &data[1];
        ptrs[2] = &data[2];
        ptrs[3] = &data[3];
    }
    
    #include <stdio.h>
    
    void dump(int num, struct S ptr)
    {
        printf("%d: %2x %2x %4x\n", num,
               ptr.cParam1,
               ptr.cParam2,
               ptr.iParam3);
    }
    
    void display(void)
    {
        int i;
    
        for (i=0; i < SIZE; i++)
        {
            dump(i, *ptrs[i]);
        }
    
        puts("");
    
        for (i=0; i < SIZE; i++)
        {
            struct S tmp = *ptrs[i];
    
            dump(i, tmp);
        }
    
        puts("");
    
        /* non-loop version */
        {
            struct S tmp;
    
            tmp = *ptrs[0];        dump(0, tmp);
            tmp = *ptrs[1];        dump(1, tmp);
            tmp = *ptrs[2];        dump(2, tmp);
            tmp = *ptrs[3];        dump(3, tmp);
        }
        puts("");
    }
    
    int main(void)
    {
        set();
        display();
    
        printf("sizeof  ptrs       == %d\n", (int)sizeof ptrs);
        printf("sizeof &ptrs[0]    == %d\n", (int)sizeof &ptrs[0]);
        printf("sizeof(struct S *) == %d\n", (int)sizeof(struct S *));
    
        puts("");
    
        {
            struct S *p1 = &data[1];
            struct S *p2 = &data[2];
    
            char *cp1 = (char *)p1;
            char *cp2 = (char *)p2;
    
            printf(" p2 -  p1 = %d (1 expected)\n", (int)(p2 - p1));
            printf("cp2 - cp1 = %d (4 expected)\n", (int)(cp2 - cp1));
        }
    }
    

     

  • It looks like you are correct that values read out from the pointer array are still correct even though the array elements in the watch window are wrong. I guess this makes the bug more of an annoyance than anything else.

    We should try to get this thread moved to the CCS forum since it looks like this is a parsing issue with the watch window and not something in the compiler/platform. Thanks for catching that!

  • Moved to Code Composer forum. Also posted reply to this in a related thread: http://e2e.ti.com/support/development_tools/f/81/p/31176/108894.aspx#108894

  • It is already an old thread, but it seems that issue was not fixed completely.

    Look at this:

    Of course, I'm referring to 

    timeBetweenCurvesInFlash = (uint16_t *) (paramsAddress+3);
    derefTimeBetweenCurvesInFlash = *timeBetweenCurvesInFlash;

    and their values in watch window