1

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.

Bilal Siddiqui
  • 349
  • 3
  • 17
Frotz
  • 535
  • 4
  • 21
  • You probably should be casting to `unsigned char *` rather than `unsigned char`, since `getstuff` expects a `unsigned char *`. It also looks like you're missing a closing paren on your call to getstuff. Finally, have you tried seeing what `sizeof mystruct_t` is (by printing or logging it)? – CoffeeTableEspresso Aug 10 '18 at 23:09
  • After the compiler complaints, I showed what happened when I cast to ```unsigned char *```. ```sizeof(mystruct_t)``` is 44, same as ```buffer[]```. – Frotz Aug 10 '18 at 23:14
  • how do you know you're getting back 21900 to 22060 bytes? – CoffeeTableEspresso Aug 10 '18 at 23:17
  • 2
    I think that the messages are self explanatory. You assign char variable with pointer – 0___________ Aug 10 '18 at 23:19
  • @P__J__ I think the messages are self explanatory as well, but OP seems to still be having problems. – CoffeeTableEspresso Aug 10 '18 at 23:20
  • @CoffeeTableEspresso if yes I wrote the micro answer – 0___________ Aug 10 '18 at 23:22
  • references aren't the same as pointers, they dont figure out the referencing and de-referencing for you... `someval = *somePointer` to dereference, `func(&some_value)` to pass by address – Grady Player Aug 10 '18 at 23:35
  • @CoffeeTableEspresso libusb_bulk_transfer() returns the bytes transferred as a reference. – Frotz Aug 10 '18 at 23:48
  • Not clear what you mean with "pass by reference". C does not support references. It's **always** pass-by-value. And this wildly casting looks very much like invitation to undefined behaviour. – too honest for this site Aug 10 '18 at 23:55
  • @Frotz: Definitively **not**, see ^ – too honest for this site Aug 10 '18 at 23:56
  • This is not a typecasting issue, rather this is (de)serialization issue. You get a compact stream of data from outside (USB device) and unpack it to a certain local (native) struct. When you look at the issue in this aspect, a decent portable solution becomes obvious (extract members manually one by one, or find something on github) – ddbug Aug 12 '18 at 02:02

1 Answers1

4

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));
0___________
  • 60,014
  • 4
  • 34
  • 74