Co robią pojedyncze cudzysłowy w C ++, gdy są używane z wieloma znakami?


Odpowiedzi:


283

To dosłowny znak złożony z wielu znaków. 1952805748jest 0x74657374, który rozkłada się jako

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

Edytować:

Standard C ++, §2.14.3 / 1 - Literały znakowe

(...) Zwykły literał znakowy zawierający więcej niż jeden znak c jest literałem wieloznakowym. Literał wieloznakowy ma typ int i wartość zdefiniowaną w implementacji.


11
Nie wspomniałeś, że jest to implementacja zdefiniowana.
— Thomas Bonini,

2
Przypuszczam, że najśmieszniejsze w tej definicji jest to, że sizeof(int)zdefiniowano również implementację. Tak więc nie tylko zdefiniowano implementację kolejności pamięci, ale także jej maksymalną długość.
— bobobobo

74

Nie, to nie jest adres. Jest to tak zwana postać wielobajtowa.

Zazwyczaj są to wartości ASCII czterech połączonych znaków.

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

Więc 0x74657374 to 1952805748.

Ale może to być także 0x74736574 na innym kompilatorze. Oba standardy C i C ++ mówią, że wartość znaków wielobajtowych jest zdefiniowana implementacja . Tak więc ogólnie jego użycie jest zdecydowanie odradzane.


Czy długość takiego wielobajtowego znaku jest ograniczona do 4 bajtów? Czy to reprezentuje int zapisane jako znaki?
— Giorgio

2
@Giorgio: Standard mówi tylko, że jego implementacja jest zdefiniowana, bez dalszych szczegółów. W praktyce, ponieważ intna większości maszyn są 4 bajty, nie sądzę, aby warto było używać więcej niż 4 bajtów. Tak, miał to być wygodny sposób na zapisanie niektórych stałych, ale niestety różne kompilatory interpretują go inaczej, więc w dzisiejszych czasach większość stylów kodowania zniechęca do jego używania.
— chys,

2
@chys: A fakt, że jest on zdefiniowany w implementacji, oznacza, że ​​nie jest nawet wymagany spójność. Kompilator zgodny może nadać wszystkim literałom wieloznakowym wartość 0, na przykład (choć byłoby to nieprzyjazne).
— Keith Thompson,

2
Należy zapytać, dlaczego ta zwariowana funkcja istnieje w standardzie. Wydaje się, że jest to tak rzadki przypadek użycia, mimo to implementacja jest zdefiniowana, i można to zrobić całkiem wyraźnie za pomocą zwykłego przesuwania bitów i / lub w razie potrzeby.
— Boann

1
@Boann Tak , dokładnie moje sentymenty. Ale możesz bezpiecznie używać go w przełącznikach i tak dalej, ponieważ bezpośrednie porównanie ==powinno sprawdzić
— bobobobo

18

Zwykły literał znakowy, który zawiera więcej niż jeden znak c-char, jest literałem wieloznakowym. Literał wieloznakowy ma typ int i wartość zdefiniowaną w implementacji.

Zachowanie zdefiniowane w implementacji musi być udokumentowane przez implementację. na przykład w gcc można go znaleźć tutaj

Kompilator ceni znak wieloznakowy na raz stałą, przesuwając poprzednią wartość o liczbę bitów na znak docelowy, a następnie orientując się we wzorcu bitowym nowego znaku obciętego do szerokości celu postać. Ostateczny wzorzec bitowy ma typ int i dlatego jest podpisany, niezależnie od tego, czy pojedyncze znaki są podpisane, czy nie.

Sprawdź wyjaśnienia na tej stronie, aby uzyskać więcej informacji


10

To naprawdę tylko ints. Są szeroko stosowane w enumie Core Audio API, na przykład w CoreAudioTypes.hpliku nagłówkowym,

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

Wiele mówi się o tym, że nie jest się „niezależnym od platformy”, ale kiedy używasz interfejsu API stworzonego dla konkretnej platformy, która dba o przenośność. Sprawdzanie równości na tej samej platformie nigdy nie zawiedzie. Te enumwartości są łatwiejsze do odczytania i faktycznie zawierają swoją tożsamość w wartości , co jest całkiem miłe.

To, co próbowałem zrobić poniżej, to owinięcie literału znaku wielobajtowego, aby można go było wydrukować (działa na Macu). Dziwne jest to, że jeśli nie zużyjesz wszystkich 4 znaków, wynik staje się błędny poniżej ...

#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;
}

6
„Sprawdzanie równości na tej samej platformie nigdy nie zawiedzie”. Może. Zaktualizuj do Visual Studio xyz i ugryź się w język. Ta biblioteka podjęła straszną decyzję.
— Wyścigi lekkości na orbicie

@LightnessRacesinOrbit „Uaktualnij do Visual Studio xyz i ugryź się w język”. Core Audio API to systemowy interfejs audio systemu OS X, więc nie ma to znaczenia.
— Jean-Michaël Celerier

5
@ Jean-MichaëlCelerier: Fine; uaktualnij wersję OSX Clang i ugryź się w język ...
— Lekkość ściga się na orbicie

1

Ten rodzaj funkcji jest naprawdę dobry, gdy budujesz parsery. Rozważ to:

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

Ten kod prawdopodobnie będzie działał tylko na konkretnej endianowości i może działać w różnych kompilatorach

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.