Skip to content
Advertisement

Casting problems with passing a struct by reference instead of a pointer to a buffer

I get casting errors when passing a struct by reference. Passing a pointer to a buffer works fine. The function getstuff() is actually libusb_claim_interface() with irrelevant parts removed. I am trying to get a chunk of data back from a USB device plugged into a Linux machine.

The data comes in according to this struct:

typedef struct mystruct {
  unsigned char a;
  unsigned short b;
  unsigned char c;
  unsigned char d;
  ... /* 40 more members of unsigned char */
} mystruct_t;

However, the code I was given to work with passes a buffer of unsigned chars. The buffer then needs to set each individual struct member.

For instance:

getstuff(unsigned char *data, int length);
void foo(void)
{
  unsigned char apple;
  unsigned short banana;
  unsigned char cherry;
  unsigned char date;
  ...
  unsigned char buffer[44];

  sendstuff(...);
  getstuff(buffer, 44);
  apple = buffer[0];
  banana = buffer[1];
  cherry = buffer[2];
  date = buffer[3];
  ...
}

Rather than doing that, I want to actually define a struct (above) and pass a reference to that and then access the members sensibly, like this:

getstuff(unsigned char *data, int length);
void foo(void)
{
  unsigned char apple;
  unsigned short banana;
  unsigned char cherry;
  unsigned char date;
  ...
  mystruct_t *fruits;

  sendstuff(...);
  getstuff((unsigned char) fruits, sizeof(mystruct_t));
  apple = fruits->a;
  banana = fruits->b;
  cherry = fruits->c;
  date = fruits->d;
  ...
}

But that doesn’t work. First I get this when compiling:

warning: cast from pointer to integer of different size [-Wpointer
-to-int-cast]
(unsigned char) fruits,

warning: passing argument 3 of ‘getstuff’ makes pointer from
integer without a cast [-Wint-conversion]

Then, this (which is thrown out when libusb.h is parsed):

note: expected ‘unsigned char *’ but argument is of type ‘unsigned char’
int LIBUSB_CALL libusb_bulk_transfer(libusb_device_handle *dev_handle,

When I run the program, the device seems to send back 21906 bytes instead of the expected 44. If I cast fruits to (unsigned char *), the program compiles without complaint, but then I get back anywhere from 21900 to 22060 bytes. I could “solve” this by simply passing an array of unsigned chars like in the original code, but then doing this to copy the pointer to mystruct_t *fruits:

fruits = (mystruct_t *) buffer;

But I’d really like to know what’s going on and why I’m having so much trouble casting the struct.

Advertisement

Answer

getstuff((unsigned char) fruits, sizeof(mystruct_t)); => getstuff((unsigned char *) fruits, sizeof(*fruits));

fruits = (mystruct_t *) buffer; this one is called “pointer punning” and is unsafe, not portable and in general UB

another problem is that you do not allocate the memory for the fruits structure.

You may:

  mystruct_t fruits;
  ....
  getstuff((unsigned char *)&fruits, sizeof(fruits));

or

  mystruct_t *fruits = malloc(sizeof(*fruits));
  /* malloc checks + .... */
  getstuff((unsigned char *)fruits, sizeof(*fruits));
User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement