1
votes

Comment obtenir la valeur flottante de uint32_t?

J'utilise cette partie du code pour lire la valeur flottante du message OSC sur mon microcontrôleur. Cependant, j'obtiens l'erreur "Le pointeur de type déréférencement rompra les règles d'aliasing strict [-Wstrict-aliasing]" et aucune valeur n'est affichée sur printf. Existe-t-il une solution de contournement pour celui-ci? le marqueur est structuré comme:

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
}
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");
}

EDIT:

Donc, je reçois des données de la puce Internet des microcontrôleurs sur udp en utilisant la fonction: p>

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;
}

puis j'exécute une autre fonction pour analyser le message osc:

 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;

où A est la structure:

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

et tosc_parseMessage est:

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

puis je l'imprime avec:

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
}

où mon problème est en fonction:

char *marker;  // the current read head

J'espère que cela vous donne une meilleure vue sur le problème ... Je ne suis pas un programmeur qualifié donc j'apprécie toute aide. Le code complet de cette "bibliothèque" est disponible ici https://github.com/mhroth/tinyosc , J'essaie juste de mettre en œuvre cela dans mon microcontrôleur


12 commentaires

À quelle ligne le message se réfère-t-il exactement?


Est-ce que cela répond à votre question? Le correctif pour le déréférencement du pointeur poinçonné par type cassera l'aliasing strict


Ou ce stackoverflow.com/questions/15836866/ …


Peut-être voulez-vous: return (float) i; ?


J'ai tout essayé mais toujours pas de valeur en sortie


Dans quel format en virgule flottante la valeur est-elle stockée dans le tampon? Quel format en virgule flottante votre compilateur utilise-t-il pour stocker le type float ? Je devrais obtenir des valeurs telles que: 0,56487 0,83412, - quelle serait la représentation binaire de ces valeurs sous forme de machine? Quelle serait la valeur de cette variable uint32_t qui correspond au nombre à virgule flottante 0,56487 ?


Je ne sais vraiment pas, j'utilise Atollic Truestudio 9.3, et la puce Internet wiznet w6100 et stm32f103VCT6 .. Sur la base de ces fonctions, je suppose que je viens de lire des données simples directement à partir du tampon de la puce.


Pour le type entier, cela fonctionne parfaitement


Pouvez-vous afficher la représentation hexadécimale des octets dans les paquets et les valeurs de nombre flottant correspondantes? Comme 3 ~ 4 paquets et quels nombres à virgule flottante y sont codés. Ou similaire.


Je ne sais vraiment pas comment faire ça haha ​​... Une aide à ce sujet? Si j'imprime buf à partir de la fonction recvfrom, j'obtiens simplement mon adresse osc comme "/ composition / selectedlayer / clear" .. d'autres arguments sont trouvés en utilisant ex. fonction tosc_getNextFloat


J'ai réussi à obtenir quelque chose en printf% c mon tampon ... Pour obtenir la valeur de 0,59088, j'ai les prochains nombres hexadécimaux (octet par octet) "? ETB C xBA" (cela devrait être 3F 17 43 e9, j'ai regardé float au convertisseur hexadécimal). Le message complet est: / composition / crossfader / phaseNULNULNUL, fNULNUL? ETBCxBANULNUL‌ NULNULNULNULNULNULNU‌ L


Après quelques recherches, il devrait être 0,590877 .. L'hexagone du flotteur est donc "3f 17 43 ba"


3 Réponses :


2
votes
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;
}

7 commentaires

Donc, probablement l'entrée est vide :) Je pense au tampon pointé par «o».


Je devrais obtenir des valeurs comme: 0,56487 0,83412, le programme auquel je suis connecté envoie cela (je peux le voir via le moniteur osc)


Et qu'est-ce que vous obtenez maintenant? Toujours 0? Vérifiez le tampon * o - comment il est rempli? Comment les données y sont-elles écrites? Montrez-nous le code.


J'ai réussi à obtenir quelque chose en printf% c mon tampon ... Pour obtenir la valeur de 0,59088, j'ai les prochains nombres hexadécimaux (octet par octet) "? ETB C xBA" (cela devrait être 3F 17 43 e9, j'ai regardé float au convertisseur hexadécimal). Le message complet est: / composition / crossfader / phaseNULNULNUL, fNULNUL? ETBCxBANULNUL‌ NULNULNULNULNULNU‌ L (comme vu dans notepad ++)


Après quelques recherches, il devrait être 0,590877 .. L'hexagone du flotteur est donc "3f 17 43 ba"


Les transtypages à void * ne sont pas nécessaires.


Bien sûr. La diffusion vers void * est pour la clarté du code;)



0
votes

Si le poinçonnage de type est requis, il est préférable d'utiliser un compilateur configuré pour le prendre en charge (ce qui sur certains compilateurs non commerciaux, mais pas commercialement conçus, signifie utiliser -fno-strict- aliasing ) que de sauter à travers des cercles pour accueillir les rédacteurs de compilateurs qui refusent de reconnaître le poinçonnage de type via des pointeurs qui sont visiblement fraîchement dérivés.

Les implémentations C sont parfois utilisées à des fins où la punition de type est utile, et parfois à des fins où ce n'est pas le cas. Les auteurs de la norme ont reconnu que les rédacteurs de compilateurs devraient en savoir plus sur les besoins de leurs clients individuels que le Comité ne le pourrait, et ont ainsi permis aux implémentations de prendre en charge toutes les combinaisons de constructions qui répondraient le mieux aux besoins de leurs clients. D'une manière ou d'une autre, un mythe a émergé selon lequel Standard se caractérise comme des programmes "cassés" qui reposent sur des implémentations pour les traiter "d'une manière documentée caractéristique de l'environnement", mais une telle lecture contredit directement les intentions déclarées des auteurs du Standard.


8 commentaires

D'une manière ou d'une autre, un mythe a émergé selon lequel Standard caractérise comme des programmes "cassés" qui reposent sur des implémentations pour les traiter "de manière documentée, caractéristique de l'environnement" L'OMI est plus une réaction au "ça marche donc ça doit soyez OK "les codeurs qui ne savent pas qu'ils enfreignent les règles parce que leur plateforme leur permet de s'en tirer. Il suffit de Google "SIGBUS ARM" ou "SIGBUS SPARC" et de noter une partie de la consternation et de l'étonnement quand ils apprennent que return * ((float *) (& i)) peut et va exploser.


@AndrewHenle: Le code qui repose sur des «comportements documentés caractéristiques de l'environnement» ne devrait fonctionner comme souhaité que lorsqu'il est exécuté dans des environnements avec les comportements caractéristiques appropriés. D'un autre côté, la plupart du code ne sera jamais appelé à s'exécuter dans des environnements d'exécution avec certaines caractéristiques spécifiques connues. L'une des raisons de la popularité et de l'utilité de C est le fait que des implémentations simples peuvent permettre aux programmeurs d'exploiter les caractéristiques de l'environnement cible que les programmeurs connaissent, sans que les implémentations aient à les comprendre.


@AndrewHenle: Un coup d'œil sur les premiers résultats de vos requêtes suggère que le code essayait de charger des nombres à virgule flottante à partir d'adresses non alignées. Le code qui devra s'exécuter sur des plates-formes qui n'autorisent pas de telles charges devrait copier les données dans un emplacement correctement aligné avant de les charger, mais cela ne signifie pas qu'une telle copie devrait être nécessaire lors de l'accès à quelque chose dont l'alignement répond déjà les exigences de la cible.


@AndrewHenle: Lorsque la norme spécifie qu'il n'y a pas de différence d'accent entre un échec de spécifier le comportement d'une action et une déclaration selon laquelle l'action appelle un comportement indéfini, comment cela devrait-il être interprété dans les cas où la norme ne spécifierait pas le comportement d'une classe générale d'actions sur tout le matériel, mais des parties de la norme combinées à la documentation d'une implémentation décriraient le comportement d'une action qui est caractérisée comme UB par une autre partie de la norme. En l'absence de la dernière partie de la norme, le comportement serait défini.


... même si la norme en elle-même ne l'a pas définie. Certains auteurs de compilateurs semblent penser que "il n'y a pas de différence d'accentuation" signifie "La caractérisation comme UB l'emporte sur tout". Ma propre interprétation serait qu'en cas de tels conflits, la priorité devrait être déterminée par quelque chose en dehors de la norme (par exemple, ce qui servirait le mieux le client, ce qui servirait le mieux les caprices d'un auteur de compilateur hypothétique qui ne se soucierait pas de servir le client, etc.) Pouvez-vous offrir une interprétation plus raisonnable de l'intention de la norme?


Je suppose que l'intention de la norme est de prendre en charge le matériel où return * ((float *) (& i)); échoue. Parce qu'il existe une grande partie de ce matériel. Le fait que certains implémenteurs de compilateurs soient devenus fous avec les interprétations UB est un autre problème. Je noterai simplement qu'il y a beaucoup trop de codeurs dont la seule approche à tout problème est de lancer plus de code sur ça . Et les développeurs de GCC semblent avoir poussé cela à l'extrême - les développeurs doivent «contribuer» pour faire leur marque. Nous obtenons donc des résultats non constructifs.


@AndrewHenle: Sur du matériel où le traitement simple de la distribution échouerait, le comportement ne serait pas défini par une combinaison de parties de la norme et de la documentation d'une plate-forme, et il n'y aurait donc pas besoin de résoudre la priorité entre le (inexistant) définition et la déclaration selon laquelle l'action n'est pas définie. Si l'on lit la justification publiée, l'intention était d'éviter d'exiger que les implémentations s'abstiennent de faire des optimisations qui n'affecteraient en aucune manière le comportement du programme, mais gcc et al. ont interprété la norme comme ...


... en essayant de spécifier quelles optimisations affecteraient le comportement du programme d'une manière qui importerait, en ignorant le fait que les aspects du comportement qui pourraient ne pas avoir d'importance à certaines fins peuvent être cruciaux pour d'autres, et que les auteurs de la norme ne peuvent pas tout avoir les informations nécessaires pour les distinguer.



-1
votes

Après tout, ce n'était pas un problème de code. Oui, je reçois toujours cet avertissement (MAIS LE CODE FONCTIONNE). Le problème réel était dans l'IDE. Dans la configuration de l'éditeur de liens dans les paramètres du générateur, cela devait être ajouté: -u _printf_float. Cela a pris un mois de ma vie à comprendre ce qui se passe. Merci à tous d'avoir répondu


0 commentaires