Що роблять окремі лапки в C ++, коли вони використовуються на кількох символах?


279

Мені цікаво цей код:

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

дає мені вихід 1952805748.

Моє запитання: Вихід є адресою в пам'яті чи щось таке?


10
Зверніть увагу , що фактичне значення визначається реалізацією stackoverflow.com/questions/3960954/c-multicharacter-literal
FireAphis

Відповіді:


283

Це багатозначний буквал. 1952805748є 0x74657374, що розкладається як

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

Редагувати:

Стандарт C ++, §2.14.3 / 1 - Літерали символів

(...) Звичайний буквений символ, який містить більше одного c-char, є багатошаровим літералом. Літерал мультихарактер має значення int та значення, визначене реалізацією.


11
Ви не згадали, що це визначено реалізацією.
Томас Боніні

2
Я вважаю, що найсмішнішим у цьому визначенні є те, що sizeof(int)також визначено реалізацію. Таким чином, визначається не тільки виконання порядку зберігання, але і максимальна довжина їх.
bobobobo

74

Ні, це не адреса. Це так званий багатобайтовий символ.

Зазвичай це значення ASCII чотирьох символів разом.

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

Отже 0x74657374 - це 1952805748.

Але це може бути і 0x74736574 в іншому компіляторі. Обидва стандарти C і C ++ кажуть, що значення багатобайтових символів визначено реалізацією . Тож загалом його використання сильно не рекомендується.


Чи обмежена довжина такого багатобайтового символу 4 байтами? Тобто він представляє собою int, записаний як символи?
Джорджіо

2
@Giorgio: Стандарт говорить лише про те, що визначено реалізацію, без деталей. На практиці, оскільки intна більшості машин 4 байти, я не думаю, що має сенс використовувати більше 4 байт. Так, це було призначено для зручного запису деяких констант, але, на жаль, різні компілятори інтерпретують це по-різному, тому в наш час більшість стилів кодування відлякує його використання.
chys

2
@chys: А те, що це визначено реалізацією, означає, що навіть не потрібно бути послідовним. Відповідний компілятор може дати всім багатохарактерним літералам значення 0, наприклад (хоча це було б недобросовісно).
Кіт Томпсон

2
Потрібно запитати, чому ця приємна функція існує в стандарті. Схоже, такий рідкісний випадок використання, все одно визначений реалізацією, і це може бути зроблено досить чітко за допомогою звичайного зсуву бітів і або необхідності.
Боан

1
@Boann Так , мої настрої точно. Але ви можете сміливо використовувати його в перемикачах та інше, оскільки пряме порівняння ==слід перевірити
bobobobo

18

Звичайний буквений символ, який містить більше одного c-char, є багатоканальним літералом. Літерал мультихарактер має значення int та значення, визначене реалізацією.

Поведінка, визначена реалізацією, повинна бути задокументована реалізацією. наприклад, у gcc ви можете знайти його тут

Компілятор оцінює константу символів для багатозначних символів за один раз, зміщуючи попереднє значення, залишене на кількість біт на цільовий символ, а потім або -ing у бітовій схемі нового символу, усіченої на ширину цілі характер. Кінцевий біт-шаблон задається типу int, тому він підписується, незалежно від того, підписані окремі символи чи ні.

Перегляньте пояснення на цій сторінці для отримання більш детальної інформації


10

Вони справді просто ints. Вони широко використовуються в переліках Core Audio API, наприклад, у CoreAudioTypes.hфайлі заголовка,

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

Існує багато балачок про те, що це не "незалежна платформа", але коли ви використовуєте api, створений для певної платформи, який дбає про портативність. Перевірка рівності на одній платформі ніколи не провалиться. Ці enumзначення d легше читати, і вони насправді містять свою ідентичність у своїй вартості , що дуже приємно.

Що я намагався зробити нижче, це обернути багатобайтовий буквений символ, щоб він міг бути надрукований (на Mac це працює). Дивна річ, якщо ви не використовуєте всі 4 символи, результат стає неправильним нижче.

#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
"Перевірка рівності на одній платформі ніколи не провалиться." Це могло б. Перейдіть на Visual Studio xyz і покусайте язик. Ця бібліотека прийняла жахливе рішення.
Гонки легкості по орбіті

@LightnessRacesinOrbit "Оновіть до Visual Studio xyz і кусайте мову". Core Audio API - це системний аудіо API OS X, тому це не актуально.
Jean-Michaël Celerier

5
@ Jean-MichaëlCelerier: Чудово; оновіть свою версію OSX Clang і покусайте язик ...
Гонки легкості в орбіті

1

Така функція справді хороша, коли ви будуєте парсери. Врахуйте це:

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

Цей код, ймовірно, працює лише на певній цілеспрямованості та може розбиватися на різні компілятори

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.