C argument of type * is incompatible with parameter of type *

985 Views Asked by At

I'm trying to make HID on STM32 board. But i stuck with next problem: I don't understand where my mistake, i passing a pointer to struct which contains data for report function, but when i try to compile code i get next messsage: argument of type "keyboardHID *" is incompatible with parametr of type "uint8_t *" I write code in the same way like man from this video https://www.youtube.com/watch?v=tj1_hsQ5PR0. In his case, this is not a critical error and code compiles.

My struct:

typedef struct
{
    uint8_t MODIFIER;
    uint8_t RESERVED;
    uint8_t KEYCODE1;
    uint8_t KEYCODE2;
    uint8_t KEYCODE3;
    uint8_t KEYCODE4;
    uint8_t KEYCODE5;
    uint8_t KEYCODE6;
} keyboardHID;

keyboardHID keyboardhid = {0,0,0,0,0,0,0,0}; // it should be like this, not differently

Code that modifies structure elements and sends reports to the computer:

keyboardhid.MODIFIER = 0x02;  // left Shift
        keyboardhid.KEYCODE1 = 0x04;  // press 'a'
        keyboardhid.KEYCODE2 = 0x05;  // press 'b'
        USBD_HID_SendReport(&hUsbDeviceFS, &keyboardhid, sizeof (keyboardhid));
        HAL_Delay (50);
        
        keyboardhid.MODIFIER = 0x00;  // shift release
        keyboardhid.KEYCODE1 = 0x00;  // release key
        keyboardhid.KEYCODE2 = 0x00;  // release key
        USBD_HID_SendReport(&hUsbDeviceFS, &keyboardhid, sizeof (keyboardhid));
        HAL_Delay (1000);
1

There are 1 best solutions below

0
On

C allows implicit pointer conversions only to void*. Types uint8_t and keyboardHID are not compatible, neither their pointer. I assume that uint8_t is unsigned char but C standard does not require it.

Usually, functions that process memory directly should use void* like memcpy() or memset() but it looks that USBD_HID_SendReport() is not following this convention.

You can:

  1. Cast &keyboardhid to uint8_t*. It's safe because character types have the least alignment requirements. Moreover, characters are an explicit exception to strict aliasing rules.

  2. Use &keyboardhid.MODIFIER. C standard requires the address of the structure to be the same as an address of its first element. IMO, it is the most obscure way.

  3. Use an union.

union {
  keyboardHID keyboardhid;
  uint8_t bytes[sizeof(keyboardHID)];
} u;

And pass u.bytes to USBD_HID_SendReport().

I would go for option 1 as it is the simplest and safe. Option 3 will be the best if keyboardhid had to be cast to something other than void* or a pointer to character type (i.e. uint32_t*).