¿Qué hacen las comillas simples en C ++ cuando se usan en varios caracteres?

Respuestas:

283

Es un literal de varios caracteres. 1952805748es decir 0x74657374, que se descompone como

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

Editar:

Estándar C ++, §2.14.3 / 1 - Literales de caracteres

(...) Un literal de caracteres ordinario que contiene más de un c-char es un literal de varios caracteres. Un literal de varios caracteres tiene el tipo int y el valor definido por la implementación.

K-Ballo
fuente
11
No mencionó que esta es una implementación definida.
Thomas Bonini
2
Supongo que lo más divertido de esa definición es que sizeof(int)su implementación también está definida. Por lo tanto, no solo se define la implementación de la orden de almacenamiento, sino también la longitud máxima de estos.
bobobobo
74

No, no es una dirección. Es el llamado personaje multibyte.

Por lo general, son los valores ASCII de los cuatro caracteres combinados.

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

Entonces 0x74657374 es 1952805748.

Pero también puede ser 0x74736574 en algún otro compilador. Los estándares C y C ++ dicen que el valor de los caracteres multibyte está definido por la implementación . Por lo general, su uso está fuertemente desaconsejado.

chys
fuente
¿La longitud de dicho carácter de varios bytes está limitada a 4 bytes? Es decir, ¿representa un int escrito como caracteres?
Giorgio
2
@Giorgio: El estándar solo dice que su implementación está definida, sin más detalles. En la práctica, dado que intson 4 bytes en la mayoría de las máquinas, no creo que tenga sentido usar más de 4 bytes. Sí, estaba destinado a ser una forma conveniente de escribir algunas constantes, pero desafortunadamente diferentes compiladores lo han estado interpretando de manera diferente, por lo que hoy en día la mayoría de los estilos de codificación desalientan su uso.
Chys
2
@chys: Y el hecho de que esté definida por la implementación significa que ni siquiera es necesario que sea coherente. Un compilador conforme podría dar a todos los literales de múltiples caracteres el valor 0, por ejemplo (aunque eso sería hostil).
Keith Thompson el
2
Uno tiene que preguntarse por qué esta característica loca existe en el estándar. Parece un caso de uso tan raro, la implementación se define de todos modos, y se puede hacer con bastante claridad con el cambio de bits normal y el orden si es necesario.
Boann
1
@Boann , mis sentimientos exactamente. Pero puede usarlo de forma segura en interruptores y demás, ya que la comparación directa ==debería
verlo
18

Un literal de caracteres ordinario que contiene más de un c-char es un literal de varios caracteres. Un literal de varios caracteres tiene el tipo int y el valor definido por la implementación.

El comportamiento definido de implementación debe ser documentado por la implementación. por ejemplo en gcc puedes encontrarlo aquí

El compilador valora un carácter de varios caracteres constante un carácter a la vez, desplazando el valor anterior dejado por el número de bits por carácter de destino, y luego ordenando el patrón de bits del nuevo carácter truncado al ancho de un objetivo personaje. El patrón de bits final recibe el tipo int y, por lo tanto, está firmado, independientemente de si los caracteres individuales están firmados o no.

Consulte la explicación en esta página para obtener más detalles.

Mouna Cheikhna
fuente
10

En realidad son solo ints. Se usan ampliamente en la enumeración de Core Audio API, por ejemplo, en el CoreAudioTypes.harchivo de encabezado,

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

Se habla mucho de que esto no sea "independiente de la plataforma", pero cuando estás usando una API hecha para una plataforma específica, a quién le importa la portabilidad. Verificar la igualdad en la misma plataforma nunca fallará. Estos enumvalores 'd son más fáciles de leer y en realidad contienen su identidad en su valor , lo cual es bastante agradable.

Lo que he intentado hacer a continuación es envolver un literal de caracteres multibyte para que se pueda imprimir (en Mac, esto funciona). Lo extraño es que, si no usa los 4 caracteres, el resultado se vuelve incorrecto a continuación.

#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
fuente
66
"Comprobar la igualdad en la misma plataforma nunca fallará". Que podría. Actualice a Visual Studio xyz y muerda su lengua. Esta biblioteca ha tomado una decisión terrible .
ligereza corre en órbita el
@LightnessRacesinOrbit "Actualiza a Visual Studio xyz y muerde tu lengua". Core Audio API es la API de audio del sistema OS X, por lo que esto no es relevante.
Jean-Michaël Celerier
55
@ Jean-MichaëlCelerier: Bien; actualiza tu versión OSX Clang y muerde tu lengua ...
Lightness Races in Orbit
1

Este tipo de característica es realmente buena cuando está creando analizadores. Considera esto:

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

Es probable que este código solo funcione en aplicaciones específicas y podría dividirse en diferentes compiladores

Ayende Rahien
fuente