CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

[Solved]CCS compiler: passing address of pointer to function

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
allenhuffman



Joined: 17 Jun 2019
Posts: 552
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

[Solved]CCS compiler: passing address of pointer to function
PostPosted: Sun Dec 08, 2019 9:47 pm     Reply with quote

I was bringing over some code I used previously on an ARM system (and also PC) and found odd behavior on the CCS compiler.

The functions take the *address* of a pointer to a buffer, then either get or put data in the buffer and increment the pointer accordingly.
Code:
uint8_t buffer[32];
uint8_t *ptr = &buffer[0];

value = get8 (&ptr);
value = get16 (&ptr);
value = get32 (&ptr);

...and so on.

There are corresponding functions that put bytes into the buffer:
Code:
put8 (&ptr, 0x22);
put16 (&ptr, 0x1234);
put32 (&ptr, 0xaabbccdd);


The ptr pointers returns adjusted forward.

On the PIC24, the put routines seem to work fine, but I get a crash on the gets. Here's example code:

Code:
void put8 (uint8_t **destPtr, uint8_t value)
{
    // This doesn't work for me on the CCS compiler.
    //memcpy (*destPtr, &data, sizeof(data));

    (*destPtr)[0] = value;
    (*destPtr) += sizeof(value);
}

uint8_t get8 (uint8_t **sourcePtr)
{
    uint8_t value;

    //memcpy(&value, *sourcePtr, sizeof(value));
    //(*(uint8_t*)sourcePtr) += sizeof(value);

    value = (*sourcePtr)[0];
    (*sourcePtr)++;

    return value; // TODO: add error checking!
}

Here is a small code sample that crashes on my system:
Code:
    uint8_t buffer[32];
    uint8_t *ptr;
    unsigned int    value1, value2, value3;

    memset (buffer, 0x0, sizeof(buffer));
    ptr = &buffer[0];
   
    // Put some data in.
    put8 (&ptr, 0x11);
    put8 (&ptr, 0x22);
    put8 (&ptr, 0x33);
   
    // Rewind and get the data out.
    ptr = &buffer[0];
   
    value1 = get8 (&ptr);
    value2 = get8 (&ptr);
    value3 = get8 (&ptr);

The pointers seem to be as I expect. I did this quick test:
Code:
void pointerTest (uint8_t **ptrPtr)
{
    printf (" ptrPtr = 0x%x\r\n", (unsigned int)ptrPtr);
    printf ("*ptrPtr = 0x%x\r\n", (unsigned int)*ptrPtr);
}

void main (void)
{
    uint8_t buffer[32];
    uint8_t *ptr;
   
    memset (buffer, 0x0, sizeof(buffer));
   
    ptr = &buffer[0];
   
    printf (" ptr = 0x%x\r\n", (unsigned int)ptr);
    printf ("&ptr = 0x%x\r\n", (unsigned int)&ptr);
   
    pointerTest (&ptr);

    while(1);
}

And I see what I expect:
Code:
ptr = 0x1072
&ptr = 0x1092
ptrPtr = 0x1092
*ptrPtr = 0x1072


But something is wacky with how I am dereferencing the pointer in my routine. The code worked on OS-9 with Microware's Ultra-C compiler (back in the late 90s!), Eclipse/GCC for ARM, GCC/x86, and a few others I've done this.

Can someone see something glaringly obvious I am doing wrong?

Thanks, much.
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?


Last edited by allenhuffman on Mon Dec 09, 2019 1:54 pm; edited 1 time in total
Ttelmah



Joined: 11 Mar 2010
Posts: 19498

View user's profile Send private message

PostPosted: Mon Dec 09, 2019 2:56 am     Reply with quote

Your posted code compiles and runs without crashing for me.

However I can see it is likely to crash for the 16bit and 32bit versions.
Are you sure it is not these that have the problems?.
The reason is alignment. Problem is that when you try to fetch a
16bit or 32bit value using the pointer, it is a byte aligned pointer, and
has been incremented to an odd address. A fetch of a 16bit or 32bit
value, requires the pointer to be word aligned.

If it is the 16 and 32bit versions that are the crash, then the answer is to
fetch byte values and then convert these into the 16bit ot 32bit values
after fetching these. Using possibly a union or make16.

Your 'memcpy' line is different, since there is nothing called 'data' in the
function....

Just as a demo, done it using memcpy:
Code:

void put8 (uint8_t **destPtr, uint8_t value)
{
   
    // This doesn't work for me on the CCS compiler. - works for me
    memcpy (*destPtr, &value, sizeof(value));

    (*destPtr) += sizeof(value);
}

void put16 (uint8_t **destPtr, uint16_t value)
{
    memcpy(*destptr, &value, sizeof(value));   
    (*destPtr) += sizeof(value);
}

void put32 (uint8_t **destPtr, uint32_t value)
{
    memcpy(*destptr, &value, sizeof(value));     
    (*destPtr) += sizeof(value);
}

uint8_t get8 (uint8_t **sourcePtr)
{
    uint8_t value;

    memcpy(&value, *sourcePtr, sizeof(value));
    (*sourcePtr)++;

    return value; // TODO: add error checking!
}   

uint16_t get16 (uint8_t **sourcePtr)
{
    uint16_t dest;

    memcpy(&dest, *sourcePtr, sizeof(dest));
    (*sourcePtr) += sizeof(dest);

    return dest; // TODO: add error checking!
}

uint32_t get32 (uint8_t **sourcePtr)
{
    uint32_t dest;
   
    memcpy(&dest, *sourcePtr, sizeof(dest));
    (*sourcePtr) += sizeof(dest);

    return dest; // TODO: add error checking!
}


Merrily works for me and returns the right values.
allenhuffman



Joined: 17 Jun 2019
Posts: 552
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Mon Dec 09, 2019 7:00 am     Reply with quote

How odd. The memcpy() for the byte always ended up with zero in the buffer, but worked fine for the others. I figured maybe you couldn’t memcpy() a byte due to the word addressing on PIC24. (Yeah, originally I had called it data, then renamed it to value but didn’t change the commented out code.)

I wonder if memcpy() has issues on odd bye alignment on PIC24. I’ll consult the manual. I didn’t consider that could be an issue..
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?
Ttelmah



Joined: 11 Mar 2010
Posts: 19498

View user's profile Send private message

PostPosted: Mon Dec 09, 2019 7:13 am     Reply with quote

What compiler version are you on?.
I was testing with 5.091, and the bytes were all copied OK.
allenhuffman



Joined: 17 Jun 2019
Posts: 552
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Mon Dec 09, 2019 7:30 am     Reply with quote

5.091. Heading to work and will do more tests.
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?
allenhuffman



Joined: 17 Jun 2019
Posts: 552
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Mon Dec 09, 2019 9:05 am     Reply with quote

No steps forward, one step back... When I try the "get8" using memcpy(), I get 00 as my result.

Code:

...snip...
    uint8_t buffer[32];
    uint8_t *ptr = &buffer[0];
   
    memset (buffer, 0x0, sizeof(buffer)); // edit: added this
    put8 (&ptr, 0x11);
    put8 (&ptr, 0x22);
    put8 (&ptr, 0x33);
    put16 (&ptr, 0xAABB);
    put32 (&ptr, 0x12345678);
   
    showBuffer (buffer, sizeof(buffer));
   
    ptr = &buffer[0];
    printf ("%2x ", get8 (&ptr));
    printf ("%2x ", get8 (&ptr));
    printf ("%2x ", get8 (&ptr));
    printf ("%2x ", get16 (&ptr));
    printf ("%2x ", get32 (&ptr));

    printf ("\r\nDone...");
...snip...


Code:
11 22 33 bb aa 78 56 34 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00 00 00 aabb 12345678
Done...

_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?
Ttelmah



Joined: 11 Mar 2010
Posts: 19498

View user's profile Send private message

PostPosted: Mon Dec 09, 2019 9:15 am     Reply with quote

Your get16, and get32 lines both need %Lx not %x or they will only
print the low byte fetched.
allenhuffman



Joined: 17 Jun 2019
Posts: 552
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Mon Dec 09, 2019 9:27 am     Reply with quote

Ttelmah wrote:
Your get16, and get32 lines both need %Lx not %x or they will only
print the low byte fetched.


Good point - I'll correct that (though it does print as expected in my case). I also copy/pasted just %02x (two digits) when I wanted 4 and 8.

The only one I am having issues with is the memcpy() of the 8-bit value.
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?
allenhuffman



Joined: 17 Jun 2019
Posts: 552
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Mon Dec 09, 2019 10:17 am     Reply with quote

I think I have gremlins. Now the put32 is not working, same code I was using when I posted the previous message with the hex dump.
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?
allenhuffman



Joined: 17 Jun 2019
Posts: 552
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Mon Dec 09, 2019 10:27 am     Reply with quote

Ttelmah wrote:
Your get16, and get32 lines both need %Lx not %x or they will only
print the low byte fetched.


I see their implementation of printf is different. I used %2x and it gave me 00, where normally you have to specify %02x to get leading zeros if the value is less than 0x10.
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?
allenhuffman



Joined: 17 Jun 2019
Posts: 552
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Mon Dec 09, 2019 12:21 pm     Reply with quote

Can someone explain this? I have three test functions that are identical, except for the data type of the second parameter:

Code:
void test8 (uint8_t **destPtr, uint8_t value)
{
    printf (" destPtr = 0x%lx\r\n"
            "*destPtr = 0x%lx\r\n"
            " value   = %lx\r\n", destPtr, *destPtr, value);
}

void test16 (uint8_t **destPtr, uint16_t value)
{
    printf (" destPtr = 0x%lx\r\n"
            "*destPtr = 0x%lx\r\n"
            " value   = %lx\r\n", destPtr, *destPtr, value);
}

void test32 (uint8_t **destPtr, uint32_t value)
{
    printf (" destPtr = 0x%lx\r\n"
            "*destPtr = 0x%lx\r\n"
            " value   = %lx\r\n", destPtr, *destPtr, value);
}


The body of each function is a copy/paste. Only the data type of the "value" parameter is changed.

Yet somehow this changes the value of "*destPtr":

Code:
    uint8_t buffer[25];
    uint8_t *ptr;
   
    ptr = &buffer[0];
   
    test8 (&ptr, 1);
    test16 (&ptr, 2);
    test32 (&ptr, 3);


I know it has to be a compiler quirk, since changing a second parameter should not affect the first, but this seems to be the root cause of my issue. It seem to be dereferencing a bad address and writing data somewhere bad and causing my crash. What's odd is that, when I ran it to capture the output, it showed the 16 version working, and 8 and 32 not. But in my real code, it's the opposite. The difference here is that ptr is not being moved, so it's always even. In my test code, the u8 is even, the u16 and u32 are odd, and the u16 is not working but the other two are.

Madness Smile

Code:
 destPtr = 0x108e
*destPtr = 0x74
 value   = 1
 destPtr = 0x108e
*destPtr = 0x1074
 value   = 2
 destPtr = 0x108e
*destPtr = 0x74
 value   = 3

_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Dec 09, 2019 12:56 pm     Reply with quote

What is your compiler version ? You rarely tell us.
allenhuffman



Joined: 17 Jun 2019
Posts: 552
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Mon Dec 09, 2019 1:24 pm     Reply with quote

It looks like I needed to nudge the compiler a bit more to make it understand what I wanted:
Code:
void put32 (uint8_t **destPtr, uint32_t value)
{
    memcpy (&(*destPtr)[0], &value, sizeof(value));
    (*destPtr) += sizeof(value);
}


But using "&(*destPtr)[0]" instead of just "(*destPtr)" it seems to work in all my test cases.

At the moment.
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?
allenhuffman



Joined: 17 Jun 2019
Posts: 552
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Mon Dec 09, 2019 1:25 pm     Reply with quote

PCM programmer wrote:
What is your compiler version ? You rarely tell us.


5.091 -- see my 7:30am post.

I always run the latest for new code development, and only revert if I find a compiler issue that requires it.

Our production code uses an older version, but since this is all-new code that will be fully validated and tested on its own, I'm working with the latest.

EDIT: Incidentally, from my days at doing support for an embedded OS company, the first thing we'd always ask is "are you using the current version?" and go from there, so I've kinda just got in the habbit of doing that myself. If there's a bug in an old version I use, but it works in the new, then it's my bad for not updating Smile
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?
allenhuffman



Joined: 17 Jun 2019
Posts: 552
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Mon Dec 09, 2019 1:53 pm     Reply with quote

Here is my final "working" functions, and my mini-test suite function for it, as well as a "passing" output:

Code:
uint8_t get8 (uint8_t **sourcePtr);
uint16_t get16 (uint8_t **sourcePtr);
uint32_t get32 (uint8_t **sourcePtr);
void getData (uint8_t **sourcePtr, uint8_t *destPtr, unsigned int destSize);

void put8 (uint8_t **destPtr, uint8_t value);
void put16 (uint8_t **destPtr, uint16_t value);
void put32 (uint8_t **destPtr, uint32_t value);
void putData (uint8_t **destPtr, uint8_t *sourcePtr, unsigned int sourceSize);

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>     // memcpy ()

uint8_t get8 (uint8_t **sourcePtr)
{
    uint8_t value;

    memcpy(&value, &(*sourcePtr)[0], sizeof(value));
    (*sourcePtr) += sizeof(value);

    return value;
}

uint16_t get16 (uint8_t **sourcePtr)
{
    uint16_t value;

    memcpy(&value, &(*sourcePtr)[0], sizeof(value));
    (*sourcePtr) += sizeof(value);

    return value;
}

uint32_t get32 (uint8_t **sourcePtr)
{
    uint32_t value;

    memcpy(&value, &(*sourcePtr)[0], sizeof(value));
    (*sourcePtr) += sizeof(value);

    return value;
}

void getData (uint8_t **sourcePtr, uint8_t *destPtr, unsigned int destSize)
{
    memcpy (destPtr, &(*sourcePtr)[0], destSize);
    (*sourcePtr) += destSize;
}

void put8 (uint8_t **destPtr, uint8_t value)
{
    memcpy (&(*destPtr)[0], &value, sizeof(value));
    (*destPtr) += sizeof(value);
}

void put16 (uint8_t **destPtr, uint16_t value)
{
    memcpy (&(*destPtr)[0], &value, sizeof(value));   
    (*destPtr) += sizeof(value);
}

void put32 (uint8_t **destPtr, uint32_t value)
{
    memcpy (&(*destPtr)[0], &value, sizeof(value));
    (*destPtr) += sizeof(value);
}

void putData (uint8_t **destPtr, uint8_t *sourcePtr, unsigned int sourceSize)
{
    memcpy (&(*destPtr)[0], sourcePtr, sourceSize);
    (*destPtr) += sourceSize;
}

void testGetPutData()
{
    uint8_t buffer[25];
    uint8_t *ptr;
   
    uint8_t u8data[] = { 0x11, 0x22, 0x33 };
    uint16_t u16data[] = { 0xaabb, 0xccdd, 0xeeff };
    uint32_t u32data[] = { 0x12345678 };
   
    memset (buffer, 0x0, sizeof(buffer));
    ptr = &buffer[0];
    showBuffer (ptr, sizeof(buffer));

    // write u8 data
    for (unsigned int idx=0; idx < sizeof(u8data)/sizeof(u8data[0]); idx++) put8 (&ptr, u8data[idx]);
    // write u16 data
    for (unsigned int idx=0; idx < sizeof(u16data)/sizeof(u16data[0]); idx++) put16 (&ptr, u16data[idx]);
    // write u32 data
    for (unsigned int idx=0; idx < sizeof(u32data)/sizeof(u32data[0]); idx++) put32 (&ptr, u32data[idx]);
    // write arbitrary sized data
    putData (&ptr, &u8data[0], sizeof(u8data));

    // Verify
    ptr = &buffer[0];
    showBuffer (ptr, sizeof(buffer));

    for (unsigned int idx=0; idx < sizeof(u8data); idx++)
    {
        uint8_t data = get8 (&ptr);
        if (data != u8data[idx]) printf ("BAD! ");
        printf ("u8 %u. read %u, expected %u\r\n", idx, data, u8data[idx]);
    }
   
    for (unsigned int idx=0; idx < sizeof(u16data)/sizeof(u16data[0]); idx++)
    {
        uint16_t data = get16 (&ptr);
        if (data != u16data[idx]) printf ("BAD! ");
        printf ("u16 %u. read %lu, expected %lu\r\n", idx, data, u16data[idx]);
    }

    for (unsigned int idx=0; idx < sizeof(u32data)/sizeof(u32data[0]); idx++)
    {
        uint32_t data = get32 (&ptr);
        if (data != u32data[idx]) printf ("BAD! ");
        printf ("u32 %u read %lu, expected %lu\r\n", idx, data, u32data[idx]);
    }

    uint8_t inBuffer[sizeof(u8data)];
    getData (&ptr, &inBuffer[0], sizeof(inBuffer));
    if (memcmp (inBuffer, u8data, sizeof(inBuffer)) != 0) printf ("BAD! ");
    printf ("data read: ");
    showBuffer (inBuffer, sizeof(inBuffer));
    printf ("expected:");
    showBuffer (u8data, sizeof(u8data));
}


OUTPUT:

Code:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
11 22 33 bb aa dd cc ff ee 78 56 34 12 11 22 33 00 00 00 00 00 00 00 00 00
u8 0. read 17, expected 17
u8 1. read 34, expected 34
u8 2. read 51, expected 51
u16 0. read 43707, expected 43707
u16 1. read 52445, expected 52445
u16 2. read 61183, expected 61183
u32 0 read 305419896, expected 305419896
data read: 11 22 33
expected:11 22 33


(Yeah, the output could be made a bit nicer; printing hex and such.)

Thanks for everyone's help here!
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group