9
votes

Signedness de carbonisation et Unicode en C ++ 0x

À partir du C ++ 0x projet de travail, les nouveaux types de char ( char16_t et char32_t ) pour la manipulation Unicode sera non signé ( uint_least16_t et uint_least32_t seront les types sous-jacents).

Mais pour autant que je peux voir (pas très loin peut-être) un type char8_t (basé sur uint_least8_t ) n'est pas défini. Pourquoi ?

Et il est encore plus confus quand vous voyez qu'une nouvelle U8 préfixe codage est introduit pour la chaîne UTF-8 littérale ... basée sur vieil ami (signe / non signé) char . Pourquoi?

Mise à jour : Il y a une proposition visant à ajouter un nouveau type: char8_t

char8_t: Un type de caractères UTF-8 et les chaînes (Version 1) http: //www.open-std. org / JTC1 / SC22 / WG21 / docs / documents / 2018 / p0482r1.html


0 commentaires

3 Réponses :


1
votes

char16_t et char32_t sont censés être utilisables pour représenter les points de code. , Il est judicieux car il n'y a pas de points de code de négatif pour ceux-ci soient non signés.

UTF-8 ne représente pas les points de code directement, donc il n'a pas d'importance si U8 type sous-jacent de 'est signé ou non.


10 commentaires

Si je veux conserver le caractère é (U + 00E9), qui est la séquence de deux octets 0xC3 0xA9, avec un tableau de char signé échouera: signed char e_acute = {} 0xC3,0xA9 => ce tronque la valeur. Donc, si votre système définit char comme signed char, il est toujours un problème. Ai-je tort ?


Très rarement vous devez saisir les octets manuellement: souvent, comme vous dites, U8 est utilisé. Donc, les octets élevés Parvenez traités comme des nombres négatifs dans ce cas.


Chris, est-il une garantie que la paire de conversions unsigned char -> signed char -> unsigned char donnera la valeur initiale? L'ancienne conversion est définie par l'implémentation et je ne pouvais pas trouver une clause qui garantirait l'aller-retour.


@avakar: Je ne sais pas pourquoi le roundtripping est important dans ce cas (à moins que je mal lu votre commentaire). La façon dont je comprends la tâche est la suivante: vous avez besoin d'un moyen de convertir un tas de char dans un tas de char16_t ou char32_t . Vous pouvez facilement élargir un au cours de cette conversion char .


Mon point est que si vous recevez des données UTF-8 de quelque part (comme une séquence de nombres dans la plage de 0 à -255, qui est comment UTF-8 est définie), vous ne pouvez pas les stocker de manière fiable dans un tableau de caractères, car la valeur que vous souhaitez obtenir par moulage retourner à unsigned char peut être différent (et je ne suis même pas sûr que CHAR_BIT est assuré d'être au moins 8). Pour la fiabilité, vous devez utiliser uint_least8_t , et pour moi, il semble utile et cohérente pour fournir char8_t typedef pour elle.


Non, vous n'interprétez UTF8 directement. Vous passez à une fonction de support d'exécution qui le convertit en un type de caractères natif, comme wchar_t. Donc, peu importe quel genre de sac d'octets que vous mettez dans.


La lecture d'un fichier UTF-8 dans un char buffer signé produira le même problème. Aussi, si votre personnage est signé, vous ne pouvez pas supposer qu'une std :: string (basic_string ) est une chaîne valide UTF-8. Je ne vois pas comment cela change même avec U8?


@avakar: Normalement, vous lisez dans les données d'octets à partir d'un fichier ou d'un réseau. Ceux-ci généralement stockés sous forme de char déjà, quelle que soit signedness est native du système. Ainsi, dans un cas signé (dans l'exemple de l'OP), 0xC3, 0xA9 est lu comme -0x3D, -0x57 (sur les systèmes de complément de deux). C'est très bien: les fonctions de conversion peuvent promouvoir encore de façon significative que dans un int, et les transformer en points de code réels de cette façon.


char 's gamme garantie pourrait être à petit que [-127 .. + 127] si elle est signée et si la mise en œuvre utilise une représentation grandeur signée au lieu de complément à deux. En fait, la plage valide de char peut être aussi petit que [0..127] si votre jeu de caractères hôte est simplement ASCII, même si je pense qu'il doit encore être d'au moins 8 bits. Lecture "octets bruts" dans un tableau de char semble donc théoriquement non-portable. Je l'ai toujours utilisé des tableaux de unsigned char quand je besoin d'un sac d'octets. Ai-je mal compris quelque chose?


Peu importe. J'ai lu que C ++ 0x a a modifié la définition de char de telle manière à exclure les représentations qui mènent à la [0..127] et [- 127 .. + 127] gammes. Donc, une fois que vous êtes sur un nouveau compilateur conforme, un tableau de char est suffisant pour maintenir un sac d'octets. Jusque-là, cependant, unsigned char est un pari plus sûr.



4
votes

char sera le type utilisé pour UTF-8 parce qu'il est redéfinie pour être sûr qu'il peut être utilisé avec elle:

Aux fins de l'amélioration du soutien pour Unicode dans les compilateurs C, définition du type char a été modifié pour être à la fois au moins la taille nécessaire pour stocker un codage de huit bits de UTF-8 et assez grand pour contenir tout membre du compilateur de base est caractères d'exécution . C'était précédemment défini comme seul ce dernier. Il y a trois encodages Unicode C ++ 0x soutiendra: UTF-8, UTF-16, et UTF-32. En plus de l'avant changements notés à la définition de char, C ++ 0x ajoutera deux nouveaux caractères types: char16_t et char32_t. Ces sont conçus pour stocker UTF-16 et UTF-32 respectivement.

Source: http://en.wikipedia.org/wiki/C%2B % 2B0x

La plupart des utilisations d'application UTF-8 car déjà de toute façon sur PC / Mac.


3 commentaires

Ne dit pas un mot de signedness.


Pourquoi le phrasé maladroit de la partie en gras? N'est pas « codage UTF-8 huit bits » redondant?


Eh bien c'est wikipedia, le libellé change souvent et peut grandement variate qualité. Cependant, je ne l'ai pas trouvé une autre source qui résument les caractéristiques liées unicode.



1
votes

Le projet de C ++ 0x ne semble pas indiquer si oui ou non les nouveaux types de caractères Unicode sont signés ou non signés. Cependant, comme d'autres l'ont déjà dit, car il n'y a pas de négatif Unicode codepoints il serait plus logique char16_t code> et char32_t code> non signé. (Là encore, il aurait été logique char code> non signé, mais nous avons eu affaire à des caractères « négatifs » depuis les années 70.)

En outre, depuis UTF-16 gammes de 0x0 par 0xFFFF (en ignorant les paires de substitution), vous auriez besoin toute la gamme d'un nombre entier de 16 bits non signé pour représenter correctement toutes les valeurs. Il serait maladroit, pour le moins, si codepoints 0x8000 par 0xFFFF étaient représentés comme des nombres négatifs avec char16_t code>. P>

Quoi qu'il en soit, jusqu'à ce que le comité C ++ 0x dit quelque chose de définitif en la matière, vous pouvez toujours vérifier votre implémentation: p>

#include <type_traits>
#include <iostream>

int main()
{
    std::cout << std::boolalpha << std::is_signed<char16_t>::value << std::endl;
}


0 commentaires