Unicode dans Delphi RAD Studio

Unicode dans DELPHI


RAD Studio 2009 modifie les chaînes ANSI en chaînes Unicode. Cette rubrique décrit ce que vous devez savoir pour convertir vos applications afin de gérer correctement les chaînes.

RAD Studio est entièrement compatible Unicode, et des modifications sont requises sur les parties de votre code qui impliquent la gestion de chaînes. Toutefois, tous les efforts ont été effectués pour minimiser ces modifications. Bien que de nouveaux types de données ont été introduits, les types de données existants ont été conservés et ils fonctionnent comme auparavant. Grâce à l'expérience maison de la conversion Unicode, les applications de développeurs existantes devraient migrer assez bien.

Types de chaîne existants


Les types de données pré-existants AnsiString et WideString fonctionnent comme auparavant, à l'exception de la taille des données.

AnsiString


Auparavant, AnsiString était le type par défaut pour les chaînes. Ce tableau présente l'emplacement des champs dans son format précédent :

Format du type de données AnsiString
Comptage de références  
Longueur  
Données chaîne (en octets)  
Terme Null 
-8  
-4  
0  
Longueur  

Pour RAD Studio, le format de AnsiString a changé. Deux nouveaux champs (CodePage et ElemSize) ont été ajoutés. Cela rend le format identique pour AnsiString et pour le nouveau type UnicodeString.

WideString


WideString était auparavant utilisé pour les données caractères multi-octets. Son format est essentiellement le même qu'un BSTR Windows. WideString est toujours approprié dans les applications COM. WideString n'utilise pas le comptage de références, et UnicodeString est ainsi plus flexible et efficace dans d'autres types d'applications.

Nouveau type String : UnicodeString


Le nouveau type string par défaut de RAD Studio est le type UnicodeString. Ce type peut contenir des données chaîne Unicode ou ANSI.

Pour Delphi, les types Char et PChar ont toujours respectivement les définitions "flottantes" WideChar et PWideChar.

Pour C++, l'option Mappage de _TCHAR en contrôle la définition flottante de _TCHAR, qui peut être wchart_t ou char.

Format du type de données UnicodeString
Page de code 
Taille d'élément 
Comptage de références  
Longueur  
Données chaîne (en éléments)  
Terme Null 
-12  
-10  
-8  
-4  
0  
Length * elementsize  

UnicodeString et AnsiString ont ce format, bien que UnicodeString préfère les données multi-octets et AnsiString préfère les données à octet unique.

UnicodeString peut être représenté comme la structure Pascal Objet suivante :

type StrRec = record CodePage: Word; ElemSize: Word; refCount: Integer; Len: Integer;
      case Integer of 1: array[0..0] of AnsiChar; 2: array[0..0] of WideChar; end; 

UnicodeString ajoute la page de code et les champs de taille élément qui décrivent le contenu de la chaîne. UnicodeString est compatible en affectation à tous les autres types chaîne. Toutefois, les affectations entre AnsiString et UnicodeString effectuent toujours les conversions appropriées vers le bas et vers le haut. Notez que l'affectation d'un type UnicodeString à un type AnsiString n'est pas recommandé et peut générer une perte de données.

Notez que AnsiString a également les champs CodePage et ElemSize.

Les données UnicodeString sont au format UTF-16 pour les raisons suivantes :
  • UTF-16 correspond au format du système d'exploitation sous-jacent.
  • UTF-16 réduit les conversions explicites/implicites supplémentaires.
  • Il offre de meilleures performances lors de l'appel de l'API Windows.
  • Avec UTF-16, le système d'exploitation n'a pas besoin d'effectuer des conversions.
  • Le BMP (Basic Multilingual Plane) contient déjà la vaste majorité des glyphes de langage actifs dans le monde et tient dans un Char UTF-16 (16 bits) unique.
  • Les paires de substitution Unicode sont analogues au jeu de caractères multi-octets (MBCS), mais plus prévisibles et standard.
  • UnicodeString peut fournir des conversions implicites sans perte, vers et depuis WideString pour les interfaces COM de marshaling.
UnicodeString offre les avantages suivants :
  • Le format interne est unifié pour Unicode et ANSI.
  • Il utilise le comptage de références.
  • Il résout un ancien problème d'application dans C++Builder.
  • L'emploi de AnsiString pour transporter les informations de codage (page de code) réduit les problèmes de perte de données potentielles avec les transtypages implicites.
  • Le compilateur garantit que les données sont correctes avant la mutation des données.

Indexation
Les instances de UnicodeString peuvent indexer les caractères. L'indexation est à base 1, comme pour AnsiString. Considérez le code suivant :

var C: Char; S: string; begin ... C := S[1]; ... end;
 
Dans un cas comme celui présenté ci-dessus, le compilateur doit s'assurer que les données dans S sont au format approprié. Le compilateur génère du code pour s'assurer que les affectations aux éléments chaîne ont le type approprié et que l'instance est unique (c'est-à-dire que le nombre de références est égal à 1) via le même appel à UniqueStringX. Pour le code ci-dessus, puisque la chaîne peut contenir des données Unicode, le compilateur doit également appeler la fonction UniqueStringX appropriée avant l'indexation dans le tableau de caractères.

Indicateurs du compilateur

 
Dans Delphi et C++Builder, vous pouvez spécifier des indicateurs de compilation pour autoriser le code Unicode et le code non-Unicode dans le même source.
Delphi
 
{$IFDEF UNICODE}
 
C++Builder
 
#ifdef _DELPHI_STRING_UNICODE
 

Résumé des modifications


  • string est maintenant mappé en UnicodeString, pas en AnsiString.
  • Char est maintenant mappé en WideChar (2 octets, pas 1 octet) et est un caractère UTF-16.
  • PChar est maintenant mappé en PWideChar.
  • Dans C++, System::String est maintenant mappé en classe UnicodeString.
  • Dans Delphi, AnsiString est mappé sur le type string par défaut précédent.

Résumé de ce qui n'a pas changé

  • AnsiString.
  • WideString.
  • AnsiChar, PAnsiChar.
  • Les conversions implicites fonctionnent toujours.
  • La page de code active de l'utilisateur contrôle le mode (ANSI contre Unicode), afin que les chaînes ANSI soient toujours supportées.
Constructions de code indépendantes de la taille des caractères



Les opérations suivantes ne dépendent pas de la taille des caractères :
  • Concaténation de chaînes :
    • "chaîne var" + "chaîne var"
    • "chaîne var" + "littéral"
    • "littéral" + "littéral"
    • Concat("chaîne" , "chaîne")
  • Fonctions de chaîne standard :
    • Length("chaîne") renvoie le nombre d'éléments char, qui peut être différent du nombre d'octets. Notez que la fonction SizeOfrenvoie le nombre d'octets, ce qui signifie que la valeur de retour de SizeOf peut différer de celle de Length.
    • Copy("chaîne", 3début", "longueur") renvoie une sous-chaîne d'éléments Char.
    • Pos("sous-chaîne","chaîne") renvoie l'indice du premier élément Char.
  • Opérateurs :
    • "chaîne" [op comparaison] "chaîne"
    • CompareStr()
    • CompareText()
    • ...
  • FillChar()
    • FillChar(Rect, SizeOf(Rect), #0)
    • FillChar(WndClassEx, SizeOf(TWndClassEx), #0). Notez que WndClassEx.cbSize := SizeOf(TWndClassEx);
  • API Windows
    • Les appels API sont initialisés par défaut à leurs versions WideString ("W").
    • Le transtypage PChar("chaîne") a une sémantique identique.



Exemple GetModuleFileName :

function ModuleFileName(Handle: HMODULE): string; var Buffer: array[0..MAX_PATH] of

      Char; begin SetString(Result, Buffer, GetModuleFileName(Handle, Buffer, Length(Buffer))); end;


Constructions de code dépendantes de la taille des caractères

Certaines opérations dépendent de la taille des caractères. Les fonctions et les fonctionnalités de la liste suivante incluent également une version "portable" quand c'est possible. Vous pouvez de façon similaire réécrire votre code afin qu'il soit portable, c'est-à-dire qu'il fonctionne à la fois avec les variables AnsiString et UnicodeString.
  • SizeOf([tableau car]) — utilisez la fonction Length([tableau car]) portable.
  • Move([tampon car]... CharCount * SizeOf(Char)) — utilisez la fonction Move([tampon car] ,,, CharCount * SizeOf(Char))portable.
  • Stream Read/Write — utilisez la fonction AnsiStringSizeOf(Char) portable ou la classe TEncoding.
  • FillChar([tableau car], [taille], [AnsiChar]) — utilisez *SizeOf(Char) si remplissage par #0, ou la fonction StringOfChar portable
  • GetProcAddress([module], [PAnsiChar]) — utilise la fonction de surcharge fournie prenant un PWideChar.
  • Transtypage ou utilisation de PChar pour l'arithmétique de pointeur — Utilisez la fonction {IFDEF} PByte = PChar portable, au début du fichier. Ou bien utilisez la directive {POINTERMATH } pour activer l'arithmétique de pointeur pour tous les pointeurs typés, afin que l'incrémentation/décrémentation se fasse par taille d'élément.

Aucun commentaire: