Porting to mbed - pointer type issue

16 Apr 2011

Hi there,

my C is pretty rusty so I felt this question was better suited to 'Hello World!' rather than the main forum. I'm currently porting an application I've hacked from the LPCXpresso examples. It compiles under the Code Red Suite and I want to port it to mbed.

I have the following code which is used to set up the callbacks for the various USB endpoints:

#define P_EP(n) ((USB_EP_EVENT & (1 << (n))) ? USB_EndPoint##n : NULL)

/* USB Endpoint Events Callback Pointers */
void (* const USB_P_EP[USB_LOGIC_EP_NUM]) (uint32_t event) = {
  P_EP(0),
  P_EP(1),
  P_EP(2),
  P_EP(3),
};

and I'm getting the following errors from the mbed compiler:

Quote:

"A value of type "void *" cannot be used to initialize an entity of type "void (*const)(std::uint32_t)" (E144)

Any pointers (boom boom) about how to modify this for the mbed compiler?

Thanks.

16 Apr 2011

Possibly:

typedef void (* const USB_P_EP_FN) (uint32_t event)

#define P_EP(n) (USB_P_EP_FN)((USB_EP_EVENT & (1 << (n))) ? USB_EndPoint##n : NULL)

/* USB Endpoint Events Callback Pointers */
USB_P_EP_FN USB_P_EP[USB_LOGIC_EP_NUM] = {
  P_EP(0),
  P_EP(1),
  P_EP(2),
  P_EP(3),
};

I haven't tried this code to be sure it'll work though.

16 Apr 2011

Similar problems.

Quote:

"Operand types are incompatible ("void (*)(std::uint32_t)" and "void *")"

16 Apr 2011

The reason that this error happens with the mbed compiler and not the Code Red Suite compiler is that it is being compiled as C++ code on mbed and as C code in the other. The suggestion that Bhaveet made above is a good solution for making C code like this work in C++. For other compilers that I have used, naming the file with a .c extension will cause the build system to treat the file as C code instead of C++ but that doesn't appear to work on mbed. It assumes that .c files are C++ code.

16 Apr 2011

Do you get the "Operand types are incompatible ..." error for the same line as before? While I had to fake some of the function pointers that weren't included in your snippet, I was able to get the following code to compile for mbed. I wouldn't try to run it as the function pointers are invalid.

#include "mbed.h"

void* USB_EndPoint0 = (void*)0;
void* USB_EndPoint1 = (void*)4;
void* USB_EndPoint2 = (void*)8;
void* USB_EndPoint3 = (void*)12;

unsigned int USB_EP_EVENT = 0xF;

typedef void (* const USB_P_EP_FN) (uint32_t event);

#define P_EP(n) (USB_P_EP_FN)((USB_EP_EVENT & (1 << (n))) ? USB_EndPoint##n : NULL)

/* USB Endpoint Events Callback Pointers */
USB_P_EP_FN USB_P_EP[4] = {
  P_EP(0),
  P_EP(1),
  P_EP(2),
  P_EP(3),
};

int main() 
{
    if (USB_P_EP[0])
    {
        USB_P_EP[0](47);
    }
    
    return 0;
}
18 Apr 2011

Actually, having tried a few other things, I noticed that the error had disappeared after the first edit by Bhaveet. I just had the same warning as I started with:

Quote:

"Operand types are incompatible ("void (*)(std::uint32_t)" and "void *")" in file "src/usbuser.c"

However, the compile fails as I have a second error where NULL is used. The function is declared as follows:

uint32_t USB_WriteEP (uint32_t EPNum, uint8_t *pData, uint32_t pkt_lngth);

and I'm getting an error:

Quote:

"Argument of type "void *" is incompatible with parameter of type "std::uint8_t *" (E167)

for the following code:

USB_WriteEP(0x80, NULL, 0);

Is there something fundamentally different about how a void pointer is treated in C vs. C++?

Thanks.

18 Apr 2011

You will need to cast the NULL to (std::uint8_t*) as well.

Yes, there is something different between the two languages. C++ enforces more type safety. ANSI C is more lenient and will implicitly cast typed pointers to void* and vice versa. One of the classic examples is using malloc. In C you can do the following:

char* pString = malloc(128);

However C++ would complain that you are trying to place a void* pointer into a char* pointer and you would need an explicit cast:

char* pString = (char*) malloc(128);

NOTE: C++ has the new operator which can be used instead of malloc and it returns the type of its operand and not just void* (It also calls the necessary constructors.)

19 Apr 2011

Thanks Adam.

01 Aug 2011

USB_WriteEP(0x80, NULL, 0);

You will need to cast the NULL to (std::uint8_t*) as well.

?????????
01 Aug 2011

USB_WriteEP(0x80, (std::uint8_t *)NULL, 0);

Now I get

"the "packed" attribute is ignored in a typedef" in file "usb.h/" "attributes ignored here" in file "adcuser.c/"

"attributes ignored here" in file "usbcore.c/"

06 Sep 2011

Is there an option to put the compiler in C mode ?