1

i use this part of code to read float value from OSC message on my microcontroller. However i get "dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]" error and no value is showed on printf. Is there any workaround for this one? marker is in struct as:

char *marker;  // the current read head
float tosc_getNextFloat(tosc_message *o) {
  // convert from big-endian (network btye order)
  const uint32_t i = ntohl(*((uint32_t *) o->marker));
  o->marker += 4;
  return *((float *) (&i));  <---- this line of code does the error
}

EDIT :

So, i recieve data from microcontrollers internet chip over udp using function:

datasize_t recvfrom(uint8_t sn, uint8_t * buf, datasize_t len, uint8_t * addr, uint16_t *port, uint8_t *addrlen) //<- general 

then i run another function to parse osc message:

tosc_parseMessage(&A, (char*) buf, received_size); //<- how i wrote parameters

where A is structure:

 typedef struct tosc_message {
    char *format;  // a pointer to the format field
    char *marker;  // the current read head
    char *buffer;  // the original message data (also points to the address)
    uint32_t len;  // length of the buffer data
} tosc_message;

and tosc_parseMessage is:

int tosc_parseMessage(tosc_message *o, char *buffer, const int len) {
  // NOTE(mhroth): if there's a comma in the address, that's weird
  int i = 0;
  while (buffer[i] != '\0') ++i; // find the null-terimated address
  while (buffer[i] != ',') ++i; // find the comma which starts the format string
  if (i >= len) return -1; // error while looking for format string
  // format string is null terminated
  o->format = buffer + i + 1; // format starts after comma

  while (i < len && buffer[i] != '\0') ++i;
  if (i == len) return -2; // format string not null terminated

  i = (i + 4) & ~0x3; // advance to the next multiple of 4 after trailing '\0'
  o->marker = buffer + i;

  o->buffer = buffer;
  o->len = len;

  return 0;
}

and then i print that out with :

void tosc_printMessage(tosc_message *osc) {
  printf("[%i bytes] %s %s",
      osc->len, // the number of bytes in the OSC message
      tosc_getAddress(osc), // the OSC address string, e.g. "/button1"
      tosc_getFormat(osc)); // the OSC format string, e.g. "f"

  for (int i = 0; osc->format[i] != '\0'; i++) {
    switch (osc->format[i]) {
      case 'f': printf(" %g", tosc_getNextFloat(osc)); break;
      case 'd': printf(" %g", tosc_getNextDouble(osc)); break;
      case 'i': printf(" %d", tosc_getNextInt32(osc)); break;
      default: printf(" Unknown format: '%c'", osc->format[i]); break;
    }
  }
  printf("\n");
}

where my problem is in function:

float tosc_getNextFloat(tosc_message *o) {
  // convert from big-endian (network btye order)
  const uint32_t i = ntohl(*((uint32_t *) o->marker));
  o->marker += 4;
  return *((float *) (&i));  <---- this line of code does the error
}

I hope this gives you better view on problem... Im not skilled programmer so i appreciate any help. Full code for this "library" could be found here https://github.com/mhroth/tinyosc , Im just trying to implement that in my microcontroller

mrunje
  • 85
  • 1
  • 6
  • Which line exactly does the message refer to? – mkrieger1 Dec 07 '19 at 10:07
  • Does this answer your question? [Fix for dereferencing type-punned pointer will break strict-aliasing](https://stackoverflow.com/questions/8824622/fix-for-dereferencing-type-punned-pointer-will-break-strict-aliasing) – mkrieger1 Dec 07 '19 at 10:09
  • Or this https://stackoverflow.com/questions/15836866/character-array-to-floating-point-conversion – mkrieger1 Dec 07 '19 at 10:12
  • 2
    Maybe you want: `return (float) i;`? – i486 Dec 07 '19 at 10:33
  • I've tried all of it but still no value on output – mrunje Dec 07 '19 at 10:50
  • In what floating point format is the value stored inside the buffer? What floating point format does your compiler use to store `float` type? `I should get values like: 0,56487 0,83412,` - what would be the binary machine-like representation of those values? What would be the value of that `uint32_t` variable that corresponds to `0,56487` floating point number? – KamilCuk Dec 07 '19 at 22:18
  • I really dont know, i use Atollic Truestudio 9.3, and w6100 wiznet internet chip and stm32f103VCT6.. Based on those funtions i guess i just read a plain data direct from buffer of chip.. – mrunje Dec 07 '19 at 22:25
  • For intiger type it works perfect – mrunje Dec 07 '19 at 22:38
  • Can you show the hexadecimal representation of bytes in packets and corresponding floating number values? Like 3~4 packets and what floating point numbers are encoded in them. Or similar. – KamilCuk Dec 07 '19 at 22:50
  • I really dont know how to do that haha... Any help on that? If i printf buf from function recvfrom i just get my osc address like " /composition/selectedlayer/clear ".. other arguments are found using ex. tosc_getNextFloat function – mrunje Dec 07 '19 at 23:13
  • I've managed to get something by printf %c my buffer... To get value of 0.59088 i have next hex numbers (byte by byte) " ? ETB C xBA" (this should be 3F 17 43 e9, ive looked at float to hex converter).. Full message is : /composition/crossfader/phaseNULNULNUL,fNULNUL?ETBCxBANULNULNULNULNULNULNULNULNUL – mrunje Dec 08 '19 at 20:55
  • After some investigation it should be 0.590877.. So hex of float is " 3f 17 43 ba " – mrunje Dec 08 '19 at 21:37

3 Answers3

2
float tosc_getNextFloat(tosc_message *o) {
  // convert from big-endian (network btye order)
  const uint32_t i = ntohl(*((uint32_t *) o->marker));
  o->marker += 4;

  float tmp = 0;
  memcpy((void *)&tmp, (void *)&i, sizeof(uint32_t));
  return tmp;
}
VillageTech
  • 1,968
  • 8
  • 18
  • So, probably the input is empty :) I'm thinking about buffer pointed by 'o' . – VillageTech Dec 07 '19 at 11:00
  • I should get values like: 0,56487 0,83412, the program im connected to is sending that out ( i can see that through osc monitor) – mrunje Dec 07 '19 at 11:19
  • And what you get now? Always 0? Check buffer *o - how it is filled? How data is written to it? Show us the code. – VillageTech Dec 07 '19 at 12:15
  • I've managed to get something by printf %c my buffer... To get value of 0.59088 i have next hex numbers (byte by byte) " ? ETB C xBA" (this should be 3F 17 43 e9, ive looked at float to hex converter).. Full message is : /composition/crossfader/phaseNULNULNUL,fNULNUL?ETBCxBANULNULNULNULNULNULNULNULNUL (as seen in notepad++) – mrunje Dec 08 '19 at 21:08
  • After some investigation it should be 0.590877.. So hex of float is " 3f 17 43 ba " – mrunje Dec 08 '19 at 21:37
  • The casts to `void *` are not needed. – Andrew Henle Dec 14 '19 at 02:14
  • Of course. Casting to `void *` is for code clearity ;) – VillageTech Dec 14 '19 at 09:06
0

If type punning is required, it is better to use a compiler that is configured to support it (which on some non-commercially-designed compilers, but not commercially-designed ones, means using -fno-strict-aliasing) than to jump through hoops to accommodate compiler writers that refuse to recognize type punning via pointers that are visibly freshly derived.

C implementations are sometimes used for purposes where type punning is useful, and sometimes for purposes where it isn't. The authors of the Standard recognized that compiler writers should know more about their individual customers' needs than the Committee possibly could, and thus allowed implementations to support whatever combinations of constructs would best fit their customers' needs. Somehow a myth has emerged that Standard characterizes as "broken" programs which relies upon implementations to process them "In a documented fashion characteristic of the environment", but any such reading directly contradicts the stated intentions of the Standard's authors.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • *Somehow a myth has emerged that Standard characterizes as "broken" programs which relies upon implementations to process them "In a documented fashion characteristic of the environment"* IMO that's more a reaction to the "it works so it must be OK" coders who aren't aware they're bending the rules because their platform lets them get away with it. Just Google "SIGBUS ARM" or "SIGBUS SPARC" and note some of the consternation and astonishment when they learn that `return *((float *) (&i))` can and will blow up. – Andrew Henle Dec 14 '19 at 02:18
  • @AndrewHenle: Code which relies upon "documented behaviors characteristic of the environment" should only be expected to work as desired when run in environments with the appropriate characteristic behaviors. On the other hand, most code will only ever be called upon to run in execution environments with some specific known characteristics. One of the reasons for C's popularity and usefulness is the fact that simple implementations can allow programmers to exploit characteristics of the target environment that programmers know about, without the implementations having to understand them. – supercat Dec 14 '19 at 20:41
  • @AndrewHenle: A glance at initial hits from your queries suggests that code was trying to load floating-point numbers from unaligned addresses. Code which will need to run on platforms that don't allow such loads would need to copy the data to a properly-aligned location before loading it, but that doesn't mean that such copying should be necessary when accessing something whose alignment already meets the target's requirements. – supercat Dec 14 '19 at 20:57
  • @AndrewHenle: When the Standard specifies that there is no difference in emphasis between a failure to specify the behavior of an action and a statement that the action invokes Undefined Behavior, how should that be interpreted in cases where the Standard wouldn't specify the behavior of a general class of actions on all hardware, but parts of the Standard combined with an implementation's documentation would describe the behavior of an action which is characterized as UB by some other part of the Standard. In the absence of the latter part of the Standard, the behavior would be defined.. – supercat Dec 15 '19 at 19:02
  • ...even though the Standard by itself didn't define it. Some compiler writers seem to think "there is no difference in emphasis" means "The characterization as UB trumps everything". My own interpretation would be that in case of such conflicts, priority would need to be determined by something outside the Standard (e.g. what would best serve the customer, what would best serve the whims of a hypothetical compiler writer who didn't care about serving the customer, etc.) Can you offer a more reasonable interpretation of the Standard's intent? – supercat Dec 15 '19 at 19:06
  • I'd guess offhand that the intent of the Standard is to support hardware where `return *((float *) (&i));` fails. Because there's a lot of that hardware in existence. The fact that some compiler implementers have gone crazy with UB interpretations is a separate issue. I'll just note that there are way too many coders whose [only approach to any problem is to throw more code at it](https://en.wikipedia.org/wiki/Law_of_the_instrument). And GCC's developers seem to have taken that to an extreme - developers must "contribute" to make their mark. So we get non-constructive results. – Andrew Henle Dec 16 '19 at 11:10
  • @AndrewHenle: On hardware where straightforward processing of the cast would fail, the behavior would not be defined by a combination of parts of the Standard and a platform's documentation, and there would thus be no need to resolve priority between the (non-existent) definition and the statement that the action is undefined. If one reads the published Rationale, the intention was to avoid requiring that implementations refrain from making optimizations that would not affect program behavior in any way that would matter, but gcc et al. have interpreted the Standard as... – supercat Dec 16 '19 at 16:54
  • ...trying to specify what optimizations would affect program behavior in ways that would matter, ignoring the fact that aspects of behavior that might not matter for some purposes may be crucial for others, and the authors of the Standard can't possibly have all the information necessary to distinguish them. – supercat Dec 16 '19 at 16:56
-1

After all it wasnt code problem. Yes, i still get that warning ( BUT CODE WORKS ). Actual problem was in IDE. In linker setting inside builder settings this was needed to be added : -u _printf_float . That took like month of my life figuring out what's happening. Thank you all for answering

mrunje
  • 85
  • 1
  • 6