You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: _articles/c++_literals.md
+82-14Lines changed: 82 additions & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -103,7 +103,7 @@ auto number2 = 0123; // int exprimé en octal (Base 8) (commence par 0)
103
103
auto number3 = 123'456'789; // int avec des séparateurs (C++14)
104
104
{% endhighlight %}
105
105
106
-
> **Séparateurs de chiffres**: Les apostrophes (``'``) peuvent être placées librement dans le nombre. Elles n'ont aucun impact sur la valeur et sont ignorées par le compilateur. Leur seul but est d'améliorer la lisibilité des grands nombres.
106
+
Les apostrophes (``'``) peuvent être placées librement dans le nombre. Elles n'ont **aucun impact** sur la valeur et sont ignorées par le compilateur. Leur seul but est d'améliorer la **lisibilité des grands nombres**.
107
107
108
108
> [**Attention à l'octal**](#integer-literal): Un nombre commençant par **``0``** est interprété comme de l'**octal** (Base 8).<br>
109
109
> C'est un piège classique: ``0123`` en octal vaut **``83`` en décimal** (``1*8² + 2*8¹ + 3*8⁰ = 83``).<br>
@@ -132,11 +132,11 @@ Le C++23 a introduit des suffixes spécifiques pour faciliter la manipulation de
132
132
|**``uz``** (et variantes) |[**``std::size_t``**](/articles/c++/std_size_t)| Type non signé pour les tailles d'objets. |
133
133
|**``z``**, **``Z``**|``std::make_signed_t<std::size_t>``| Version signée de ``std::size_t`` (souvent identique à ``std::ptrdiff_t``). |
134
134
135
-
> **Combinaisons de suffixes (C++23)** : Pour ``std::size_t``, n'importe quelle combinaison de **``z``** (ou ``Z``) et de **``u``** (ou ``U``) est valide : ``zu``, ``zU``, ``Zu``, ``ZU``, ``uz``, ``uZ``, ``Uz`` ou ``UZ``.
135
+
Pour ``std::size_t``, n'importe quelle combinaison de **``z``** (ou ``Z``) et de **``u``** (ou ``U``) est valide : ``zu``, ``zU``, ``Zu``, ``ZU``, ``uz``, ``uZ``, ``Uz`` ou ``UZ``.
136
136
137
-
> Le type signé produit par **``z``** est l'équivalent standard du type [**``ssize_t`` (POSIX)**](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_types.h.html). Il est très utile pour les boucles décrémentales afin d'éviter les débordements (underflow) des types non signés.
137
+
Le type signé produit par **``z``** est l'[**équivalent standard**](/articles/c++/size#les-alternatives-signées--ptrdiff_t-et-stdssize) du type [**``ssize_t`` (POSIX)**](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_types.h.html). Il est très utile pour les boucles décrémentales afin d'éviter les débordements (underflow) des types non signés.
138
138
139
-
En revanche, il n'existe toujours pas de literal pour les types à **largeur fixe** stricte (comme ``std::int64_t`` ou ``std::int32_t``). On continue d'utiliser les literals des types fondamentaux correspondants:
139
+
En revanche, il n'existe toujours pas de literal pour les types à **largeur fixe** stricte (comme ``std::int64_t`` ou ``std::int32_t``). On continue d'utiliser les literals des types fondamentaux correspondants:
140
140
{% highlight cpp %}
141
141
auto n64 = 42ll; // Type long long int (au moins 64 bits)
142
142
auto u64 = 42ull; // Type unsigned long long int (au moins 64 bits)
@@ -292,7 +292,9 @@ Elle reste présente [dans les includes de headers C portés en C++](https://en.
292
292
Le **C++11** se voit ajouter le **literal ``nullptr``** (oui, c'est bien un literal et pas une constante comme [``nullptr`` en C](#en-c-depuis-c23-nullptr)), version à partir de laquelle ``NULL`` est **redéfini en ``#define NULL nullptr``** pour bénéficier tout de même du **typage fort** sur les codes historiques.
293
293
294
294
> Bien que ``nullptr`` en C++11 et ``nullptr`` en C23 **partagent le même nom** et remplissent un rôle similaire (valeur nulle non ambiguë), ce sont deux entités distinctes, **chacune définie dans son langage respectif** avec des mécanismes internes différents.<br>
295
+
>
295
296
> Il en est de même pour ``std::nullptr_t`` en C++11 et ``nullptr_t`` en C23. Le premier étant un type propre au langage C++ **importé depuis ``<cstddef>``** tandis que le second est un **type fondamental** du langage C.<br>
297
+
>
296
298
> Ils représentent la même notion et partagent des comportements similaires, **mais ne sont ni la même valeur, ni le même type partagé entre les deux langages**.<br>
297
299
> Une **interopérabilité** reste cependant **possible, mais pas automatique**.<br>
298
300
> Ceci requiert l'utilisation de ``extern "C"``.
@@ -393,8 +395,7 @@ Ces séquences sont utilisables aussi bien dans les [**character literal**](#cha
393
395
394
396
> Notez qu'il n'est pas nécessaire d'échapper un double guillemet à l'intérieur de guillemets simples (``'"'`` est valide), ni un guillemet simple à l'intérieur de guillemets doubles (``"'"`` est valide). L'échappement n'est requis que pour lever une ambiguïté.
395
397
396
-
Voici la liste complète des [séquences d'échappement reconnues par le standard](https://en.cppreference.com/w/cpp/language/escape):
397
-
398
+
Voici la liste des [**séquences d'échappement simples**](https://en.cppreference.com/w/cpp/language/escape):
398
399
399
400
| Séquence | Signification |
400
401
| :--- | :--- |
@@ -409,14 +410,52 @@ Voici la liste complète des [séquences d'échappement reconnues par le standar
409
410
|``\'``| Guillemet simple |
410
411
|``\"``| Guillemet double |
411
412
|``\?``| Point d'interrogation |
412
-
|**``\0``**| Caractère nul utilisé comme **sentinelle** (valant **0**, équivalent à [**``NULL``**](#en-c-avant-c23-null) en langage C) |
|``\0``| Caractère nul utilisé comme **sentinelle** (valant **0**, équivalent à [**``NULL``**](#en-c-avant-c23-null) en langage C) |
417
414
418
415
> **Note sur le signal sonore (``\a``)**: L'émission d'un son dépend de votre terminal et de sa configuration. Le caractère est envoyé au flux de sortie, mais c'est à l'émulateur de terminal de décider s'il doit déclencher un "beep" système ou une notification.
419
416
417
+
#### Codes numériques et Unicode
418
+
419
+
Les [**universal character names**](https://en.cppreference.com/w/cpp/language/escape) (tableau ci-dessous) permettent de référencer un caractère par son [*code point*](https://www.unicode.org/versions/Unicode17.0.0/core-spec/chapter-2/#G25564) Unicode. Ils **évitent toute dépendance** à l'**encodage du fichier** source.
420
+
421
+
Sans ces codes, un caractère écrit "**en dur**" peut être **interprété différemment selon la machine** qui compile:
422
+
{% highlight cpp %}
423
+
// Le résultat dépend de l'encodage du fichier source
424
+
auto s = "é";
425
+
// Si le fichier source est en UTF-8 → C3 A9
426
+
// Si le fichier source est en Windows-1252 → E9
427
+
428
+
// Avec un universal character name
429
+
auto s = "\u00E9"; // // garantie de référencer le code point Unicode U+00E9
430
+
{% endhighlight %}
431
+
432
+
En revanche, **l'encodage final** du caractère dans le binaire **dépend du type de literal** ("", [u8""](#string-literal), [u""](#string-literal), [U""](#string-literal)).<br>
433
+
Seuls **les literals UTF** (u8, u, U) **garantissent l'encodage** exact des octets générés.
434
+
435
+
| Séquence | Signification |
436
+
| :--- | :--- |
437
+
|``\nnn``| Valeur **octale** (1 à 3 chiffres, ex: ``\123``) |
438
+
|``\xn...``| Valeur **hexadécimale**. ``\x`` suivi d'un **nombre arbitraire de chiffres** hexadécimaux (ex: ``\x53``), **jusqu'à un caractère non-hexadécimal**|
439
+
|``\unnnn``| Code **Unicode**. ``\u`` suivi de **4 chiffres** hexadécimaux |
440
+
|``\Unnnnnnnn``| Code **Unicode**. ``\U`` suivi de **8 chiffres** hexadécimaux |
441
+
|``\o{n...}``|**Octal délimité**¹ (C++23) |
442
+
|``\x{n...}``|**Hexadécimal délimité**¹ (C++23) |
443
+
|``\u{n...}``|**Unicode délimité**¹ (C++23) exprimé en hexadécimal |
444
+
|``\N{NAME}``|**Caractère nommé** (C++23). Permet d'utiliser un caractère par son nom officiel Unicode. |
445
+
446
+
*¹Le terme "**délimité**" signifie que la valeur est **entourée d'accolades**. Celles-ci peuvent contenir un **nombre arbitraire de chiffres**. Cette syntaxe permet une longueur libre et **évite que le compilateur ne "mange" par erreur des chiffres** appartenant au texte qui suit.*
447
+
448
+
{% highlight cpp %}
449
+
auto s0 = "\123"; // 'S' (Octal)
450
+
auto s1 = "\x53"; // 'S' (Hexadécimal)
451
+
452
+
auto s2 = "\u{1F600}"; // 😀 (Unicode délimité)
453
+
auto s3 = "\x{41}"; // 'A' (Hexadécimal délimité)
454
+
455
+
auto s4 = "\N{GREEK DELTA}"; // Δ
456
+
auto s5 = "\N{GRINNING FACE}"; // 😀
457
+
{% endhighlight %}
458
+
420
459
### Multi-caractères (Multi-character literal)
421
460
422
461
Mettre plusieurs caractères entre guillemets simples est une pratique **fortement déconseillée**:
auto s4 = L"hello"; // const wchar_t[6] (Wide character)
448
487
{% endhighlight %}
449
488
450
-
> Chaque literal de chaîne, quel que soit son encodage, se termine par une **sentinelle nulle** (``\0``) ajoutée automatiquement par le compilateur. La taille du tableau (``[6]`` ici) inclut toujours ce caractère invisible.
489
+
Chaque literal de chaîne, quel que soit son encodage, se termine par une **sentinelle nulle** (``\0``) ajoutée automatiquement par le compilateur. La taille du tableau (``[6]`` ici) inclut toujours ce caractère invisible.
451
490
452
491
### ``std::string`` literal (C++14) et ``std::string_view`` literal (C++17)
453
492
@@ -513,7 +552,7 @@ auto sv = u"hello"sv; // std::u16string_view
513
552
> À noter que la plupart de ces littéraux sont devenus [**``constexpr``**](/articles/c++/compile-time_execution) à partir du C++20.
514
553
515
554
516
-
> **Sécurité de string_view**: Par nature, un ``std::string_view`` ne garantit pas la présence d'un ``\0`` final (il se contente d'un pointeur et d'une taille). Cependant, lorsqu'il est construit à partir d'un **literal** (``"..."sv``), il pointe vers le tableau statique du binaire qui, lui, possède bien cette sentinelle. Passer ``sv.data()`` à une fonction attendant un pointeur C est donc **techniquement sûr** dans ce cas précis, bien que risqué conceptuellement.
555
+
Par nature, un ``std::string_view`` ne garantit pas la présence d'un ``\0`` final (il se contente d'un pointeur et d'une taille). Cependant, lorsqu'il est construit à partir d'un **literal** (``"..."sv``), il pointe vers le tableau statique du binaire qui, lui, possède bien cette sentinelle. Passer ``sv.data()`` à une fonction attendant un pointeur C est donc **techniquement sûr** dans ce cas précis, bien que risqué conceptuellement.
517
556
518
557
### String literal: lvalue ou prvalue ?
519
558
@@ -663,6 +702,8 @@ Les opérateurs de literals ne peuvent prendre [**que des types spécifiques**](
-**Chaînes** : Un couple ``(const T*, std::size_t)`` où ``T`` est l'un des types de caractères ci-dessus.
665
704
705
+
> **Conflits de suffixes**: Il est possible d'utiliser le même suffixe pour des catégories différentes (ex: le suffixe ``s`` utilisé pour les [**chaînes**](#stdstring-literal-c14-et-stdstring_view-literal-c17) (``"hello"s``) et pour [**chrono**](#chrono-literal-c14--c20) (``1s``)). Le compilateur ne rencontre aucune ambiguïté car il distingue les catégories par leurs paramètres (un couple ``ptr, size`` pour une chaîne contre un ``unsigned long long`` pour un nombre).
706
+
666
707
> **Le cas particulier du ``const char*``**: Un opérateur ne prenant qu'un simple ``const char*`` est utilisé **uniquement** pour les literals numériques en mode "Raw". Il n'existe pas d'équivalent pour les chaînes de caractères (**qui exigent toujours la taille en second paramètre**).
667
708
>
668
709
> Ainsi, si vous définissez un ``operator ""_suffix(const char*)``:
Pour illustrer la complexité de l'analyse lexicale du C++, voici un littéral qui combine presque toutes les fonctionnalités abordées dans cet article en une seule valeur:
762
+
763
+
{% highlight cpp %}
764
+
auto x = 0x14'2.e9'1'fp-1'3_e\u00e9l\u{d4}f;
765
+
{% endhighlight %}
766
+
767
+
Décortiquons rigoureusement ce "monstre" syntaxique:
768
+
769
+
1.**Préfixe ``0x``** : Indique que la valeur est exprimée en **hexadécimal**
0 commit comments