Que font les guillemets simples en C ++ lorsqu'ils sont utilisés sur plusieurs caractères?

279

Je suis curieux de ce code:

cout << 'test'; // Note the single quotes.

me donne une sortie de 1952805748.

Ma question: la sortie est-elle une adresse en mémoire ou quelque chose?

lucidreality
la source
10
Faites attention à ce que la valeur réelle soit définie par l'implémentation stackoverflow.com/questions/3960954/c-multicharacter-literal
FireAphis

Réponses:

283

C'est un littéral à plusieurs caractères. 1952805748est 0x74657374, qui se décompose en

0x74 -> 't'
0x65 -> 'e'
0x73 -> 's'
0x74 -> 't'

Éditer:

Norme C ++, §2.14.3 / 1 - Littéraux de caractères

(...) Un littéral de caractère ordinaire qui contient plus d'un caractère C est un littéral multicaractère. Un littéral multicaractère a un type int et une valeur définie par l'implémentation.

K-ballo
la source
11
Vous n'avez pas mentionné qu'il s'agit d'une implémentation définie.
Thomas Bonini
2
Je suppose que le plus drôle de cette définition est que l' sizeof(int)implémentation est également définie. Ainsi, non seulement l'implémentation de l'ordre de stockage est définie, mais la longueur maximale de ceux-ci l'est également.
bobobobo
74

Non, ce n'est pas une adresse. C'est le soi-disant caractère multi-octets.

Il s'agit généralement des valeurs ASCII des quatre caractères combinés.

't' == 0x74; 'e' == 0x65; 's' == 0x73; 't' == 0x74; 

Donc, 0x74657374 est 1952805748.

Mais il peut également s'agir de 0x74736574 sur un autre compilateur. Les normes C et C ++ indiquent que la valeur des caractères multi-octets est définie par l'implémentation . Donc, généralement, son utilisation est fortement déconseillée.

chys
la source
La longueur d'un tel caractère multi-octets est-elle limitée à 4 octets? Est-ce que cela représente un int écrit en caractères?
Giorgio
2
@Giorgio: La norme dit seulement que sa mise en œuvre est définie, sans plus de détails. En pratique, comme il inty a 4 octets sur la plupart des machines, je ne pense pas qu'il soit logique d'utiliser plus de 4 octets. Oui, il était destiné à être un moyen pratique d'écrire certaines constantes, mais malheureusement, différents compilateurs l'ont interprété différemment, donc de nos jours la plupart des styles de codage découragent son utilisation.
chys
2
@chys: Et le fait qu'il soit défini par l'implémentation signifie qu'il n'est même pas nécessaire d'être cohérent. Un compilateur conforme pourrait donner à tous les littéraux multicaractères la valeur 0, par exemple (bien que ce ne soit pas convivial).
Keith Thompson,
2
Il faut se demander pourquoi cette fonctionnalité loufoque existe dans la norme. Cela semble être un cas d'utilisation si rare, l'implémentation est de toute façon définie et peut être effectuée assez clairement avec un décalage de bits ordinaire et / ou si nécessaire.
Boann
1
@Boann Oui , mes sentiments exactement. Mais vous pouvez l'utiliser en toute sécurité dans les commutateurs et ainsi de suite, comme comparaison directe pour le ==vérifier
bobobobo
18

Un littéral de caractère ordinaire qui contient plusieurs caractères C est un littéral multicaractère. Un littéral multicaractère a un type int et une valeur définie par l'implémentation.

Le comportement défini par l'implémentation doit être documenté par l'implémentation. par exemple dans gcc vous pouvez le trouver ici

Le compilateur évalue une constante de caractère à plusieurs caractères un caractère à la fois, décalant la valeur précédente laissée par le nombre de bits par caractère cible, puis -ou dans le modèle binaire du nouveau caractère tronqué à la largeur d'une cible personnage. Le motif binaire final est donné de type int et est donc signé, que les caractères individuels soient signés ou non.

Consultez l'explication de cette page pour plus de détails

Mouna Cheikhna
la source
10

Ce sont vraiment des ints. Ils sont largement utilisés dans les énumérations de l'API Core Audio, par exemple, dans le CoreAudioTypes.hfichier d' en- tête,

enum
{
    kAudioFormatLinearPCM               = 'lpcm',
    kAudioFormatAC3                     = 'ac-3',
    kAudioFormat60958AC3                = 'cac3',
    kAudioFormatAppleIMA4               = 'ima4',
    kAudioFormatMPEG4AAC                = 'aac ',
    kAudioFormatMPEG4CELP               = 'celp',
} ;

Il y a beaucoup de bavardages à propos de ce qui n'est pas "indépendant de la plate-forme", mais lorsque vous utilisez une API conçue pour une plate-forme spécifique, qui se soucie de la portabilité. La vérification de l'égalité sur la même plate-forme n'échouera jamais. Ces enumvaleurs sont plus faciles à lire et contiennent en fait leur identité dans leur valeur , ce qui est plutôt agréable.

Ce que j'ai essayé de faire ci-dessous est d'envelopper un littéral de caractères multi-octets pour qu'il puisse être imprimé (sur Mac, cela fonctionne). Ce qui est étrange, c'est que si vous n'utilisez pas les 4 caractères, le résultat devient faux ci-dessous.

#include <stdio.h>

#define MASK(x,BYTEX) ((x&(0xff<<8*BYTEX))>>(8*BYTEX))

struct Multibyte
{
  union{
    int val ;
    char vals[4];
  };

  Multibyte() : val(0) { }
  Multibyte( int in )
  {
    vals[0] = MASK(in,3);
    vals[1] = MASK(in,2);
    vals[2] = MASK(in,1);
    vals[3] = MASK(in,0);
  }
  char operator[]( int i ) {
    return val >> (3-i)*8 ; // works on mac
    //return val>>i*8 ; // might work on other systems
  }

  void println()
  {
    for( int i = 0 ; i < 4 ; i++ )
      putc( vals[i], stdout ) ;
    puts( "" ) ;
  }
} ;

int main(int argc, const char * argv[])
{
  Multibyte( 'abcd' ).println() ;  
  Multibyte( 'x097' ).println() ;
  Multibyte( '\"\\\'\'' ).println() ;
  Multibyte( '/*|' ).println() ;
  Multibyte( 'd' ).println() ;

  return 0;
}
bobobobo
la source
6
"La vérification de l'égalité sur la même plate-forme n'échouera jamais." C'est possible. Passez à Visual Studio xyz et mordez votre langue. Cette bibliothèque a pris une terrible décision.
Courses de légèreté en orbite le
@LightnessRacesinOrbit "Mettez à niveau vers Visual Studio xyz et mordez votre langue." L'API Core Audio est l'API audio système d'OS X, ce n'est donc pas pertinent.
Jean-Michaël Celerier
5
@ Jean-MichaëlCelerier: Très bien; améliorez votre version OSX Clang et mordez votre langue ...
Courses de légèreté en orbite
1

Ce type de fonctionnalité est vraiment bon lorsque vous construisez des analyseurs. Considère ceci:

byte* buffer = ...;
if(*(int*)buffer == 'GET ')
  invoke_get_method(buffer+4);

Ce code ne fonctionnera probablement que sur un endianess spécifique et pourrait traverser différents compilateurs

Ayende Rahien
la source