O que aspas simples fazem em C ++ quando usadas em vários caracteres?

279

Estou curioso sobre este código:

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

me dá uma saída de 1952805748.

Minha pergunta: a saída é um endereço na memória ou algo assim?

lucidreality
fonte
10
Preste atenção que o valor real é a implementação definida stackoverflow.com/questions/3960954/c-multicharacter-literal
FireAphis

Respostas:

283

É um literal com vários caracteres. 1952805748é 0x74657374, que se decompõe como

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

Editar:

Padrão C ++, §2.14.3 / 1 - Literais de caracteres

(...) Um literal de caractere comum que contém mais de um c-char é um literal de vários caracteres. Um literal de vários caracteres possui o tipo int e o valor definido pela implementação.

K-ballo
fonte
11
Você não mencionou que esta é uma implementação definida.
Thomas Bonini
2
Suponho que a coisa mais engraçada sobre essa definição é que a sizeof(int)implementação é definida também. Portanto, não apenas a implementação da ordem de armazenamento é definida, mas também o comprimento máximo deles.
bobobobo
74

Não, não é um endereço. É o chamado caractere multibyte.

Normalmente, são os valores ASCII dos quatro caracteres combinados.

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

Então 0x74657374 é 1952805748.

Mas também pode ser 0x74736574 em algum outro compilador. Os padrões C e C ++ dizem que o valor dos caracteres multibyte é definido pela implementação . Portanto, geralmente seu uso é fortemente desencorajado.

chys
fonte
O tamanho de um caractere de vários bytes está restrito a 4 bytes? Ou seja, representa um int escrito como caracteres?
Giorgio
2
@Giorgio: O padrão diz apenas que sua implementação está definida, sem mais detalhes. Na prática, como intsão 4 bytes na maioria das máquinas, não acho que faça sentido usar mais de 4 bytes. Sim, ele pretendia ser uma maneira conveniente de escrever algumas constantes, mas, infelizmente, diferentes compiladores a interpretaram de maneira diferente; portanto, hoje em dia a maioria dos estilos de codificação desencoraja seu uso.
chys
2
@ chys: E o fato de ser definido como implementação significa que nem é necessário que seja consistente. Um compilador em conformidade pode fornecer a todos os literais de vários caracteres o valor 0, por exemplo (embora isso não seja amigável).
Keith Thompson
2
É preciso perguntar por que esse recurso maluco existe no padrão. Parece que um caso de uso tão raro, é a implementação definida de qualquer maneira, e pode ser feita de maneira bastante clara com a troca de bits comum ou se necessário.
Boann 23/02
1
@ Boann Sim , meus sentimentos exatamente. Mas você pode usá-lo com segurança em switches e outros enfeites, como comparação direta para ==deve verificar
bobobobo
18

Um literal de caractere comum que contém mais de um c-char é um literal de vários caracteres. Um literal de vários caracteres possui o tipo int e o valor definido pela implementação.

É necessário que o comportamento definido da implementação seja documentado pela implementação. por exemplo, no gcc, você pode encontrá-lo aqui

O compilador valoriza um caractere de vários caracteres, constante um caractere de cada vez, alterando o valor anterior deixado pelo número de bits por caractere de destino e, em seguida, inserindo o padrão de bits do novo caractere truncado para a largura de um destino personagem. O padrão de bits final recebe o tipo int e, portanto, é assinado, independentemente de caracteres únicos serem assinados ou não.

Verifique a explicação nesta página para mais detalhes

Mouna Cheikhna
fonte
10

Eles são realmente apenas ints. Eles são usados ​​extensivamente nas enum da API de áudio principal, por exemplo, no CoreAudioTypes.harquivo de cabeçalho,

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

Há muita conversa sobre isso não ser "independente de plataforma", mas quando você usa uma API feita para uma plataforma específica, que se preocupa com a portabilidade. A verificação da igualdade na mesma plataforma nunca falha. Esses enumvalores são mais fáceis de ler e, na verdade, contêm sua identidade em seu valor , o que é bastante bom.

O que tentei fazer abaixo é agrupar literalmente um caractere multibyte para que possa ser impresso (no Mac, isso funciona). O estranho é que, se você não usar todos os 4 caracteres, o resultado ficará errado abaixo ..

#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
fonte
6
"A verificação da igualdade na mesma plataforma nunca falha." Poderia. Atualize para o Visual Studio xyz e morda sua língua. Esta biblioteca tomou uma decisão terrível .
Lightness Races in Orbit
@LightnessRacesinOrbit "Atualize para o Visual Studio xyz e morda sua língua." A API de áudio principal é a API de áudio do sistema do OS X, portanto, isso não é relevante.
Jean-Michaël Celerier
5
@ Jean-MichaëlCelerier: Ótimo; atualize sua versão do OSX Clang e morda sua língua ...
Lightness Races in Orbit
1

Esse tipo de recurso é realmente bom quando você está construindo analisadores. Considere isto:

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

Esse código provavelmente funcionará apenas em endianess específico e pode ser dividido em diferentes compiladores

Ayende Rahien
fonte