8 votes

Écriture de fichiers binaires en C++ : la locale par défaut a-t-elle une importance ?

J'ai du code qui manipule des fichiers binaires en utilisant fstream avec le drapeau binaire activé et en utilisant les fonctions d'E/S non formatées read et write. Cela fonctionne correctement sur tous les systèmes que j'ai utilisés (les bits dans le fichier sont exactement comme prévu), mais ce sont essentiellement des systèmes anglo-saxons. Je me suis interrogé sur la possibilité que ces octets soient modifiés par un codecvt sur un autre système.

Il semble que la norme indique que l'utilisation d'E/S non formatées se comporte de la même manière que l'introduction de caractères dans le streambuf à l'aide de sputc/sgetc. Cela conduira à l'appel des fonctions overflow ou underflow dans le streambuf, et il semble que celles-ci conduisent à ce que les choses passent par un codecvt (par exemple, voir 27.8.1.4.3 dans la norme c++). Pour basic_filebuf, la création de ce codecvt est spécifiée en 27.8.1.1.5. Cela donne l'impression que les résultats dépendront de ce que basic_filebuf.getloc() renvoie.

Ma question est donc la suivante : puis-je supposer qu'un tableau de caractères écrit avec ofstream.write sur un système peut être récupéré mot pour mot avec ifstream.read sur un autre système, quelle que soit la configuration locale utilisée par l'un ou l'autre ? Je ferais les hypothèses suivantes :

  1. Le programme utilise la locale par défaut par défaut (c'est-à-dire que le programme ne modifie pas lui-même les paramètres régionaux du tout).
  2. Les deux systèmes ont CHAR_BIT 8, ont le même ordre de bits dans chaque octet, stockent les fichiers sous forme d'octets, etc.
  3. Les objets stream ont l'indicateur binaire activé.
  4. Nous n'avons pas besoin de nous soucier des différences d'endianess à ce stade. Si l'un des octets du tableau doit être interprété comme une valeur multi-octets, les conversions d'endianess seront traitées ultérieurement.

Si la locale par défaut n'est pas garantie pour passer à travers ce genre de choses sans être modifiée sur une certaine configuration du système (je ne sais pas, arabe ou autre), alors quelle est la meilleure façon d'écrire des fichiers binaires en utilisant C++ ?

1voto

Stan Points 1423

Si l'indicateur binaire est activé, tout ce que vous écrivez sera écrit dans le fichier mot à mot. Pas de conversions. La façon dont vous interprétez les octets dépend de vous (et éventuellement de la locale).

Une dernière chose : il y a une possibilité de rupture sur différents sites. Si, par exemple, votre source de données crée des données binaires basées sur la locale (et que le format de ces données change en fonction de la locale - c'est une mauvaise idée). Cela causerait des problèmes lors du chargement des données sur des machines ayant une locale différente. Il s'agit cependant d'une erreur de conception.

Si vous utilisez simplement des structures et des types de données standard qui ont le même format et la même présentation, quelle que soit la langue dans laquelle elles ont été créées, tout devrait bien se passer.

1voto

Joseph Lust Points 343

Merci pour votre aide. J'ai juste pensé qu'il pourrait être utile de poster des informations supplémentaires à ce sujet qui ne tiendraient pas dans un commentaire.

La locale par défaut des programmes C++ est toujours la locale "C" ( http://www.cplusplus.com/reference/clibrary/clocale/setlocale/ ). Si c'est la seule locale utilisée dans votre programme, cela signifie que le comportement ne dépend pas de la configuration locale particulière de la machine sur laquelle il est exécuté. Cela signifie également que les E/S non formatées pour un caractère ne subissent aucune conversion de code (wchar_t pourrait être une histoire différente cependant). Cela signifie que (compte tenu des hypothèses de la question) la lecture et l'écriture devraient permettre de récupérer des données binaires sans modification.

(d'après la lecture de la documentation) Vous pouvez définir globalement la locale de l'application pour qu'elle corresponde à la locale par défaut du système en appelant setlocale(LC_ALL,""), ce qui signifie que les flux construits à partir de ce point utiliseront la locale par défaut du système. Pour revenir à la locale "C", vous pouvez appeler setlocale(LC_ALL, "C"), ce qui signifie que les flux construits à l'avenir utiliseront cette locale. Vous pouvez également spécifier que la locale "C" doit être utilisée pour un flux déjà construit en appelant stream.imbue(locale::classic()).

0voto

Wernight Points 6086

Sous Windows, tout devrait bien se passer, mais sous d'autres systèmes d'exploitation, vous devez également vérifier les fins de ligne (par mesure de sécurité). La locale C/C++ par défaut est "C", c'est-à-dire no dépend de la locale du système.

Il ne s'agit pas d'une garantie. Comme vous le savez, les compilateurs C/C++ et leurs machines cibles varient considérablement. Vous vous attendez donc à des problèmes si vous conservez toutes ces hypothèses. La modification de la locale n'entraîne qu'un surcoût négligeable, sauf si vous essayez de le faire des centaines de fois par seconde.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X