Многосимвольный литерал в C/C++

Опубликовано: 14 Сентября, 2022

Символьными литералами для C и C++ являются char, string и их типы Unicode и Raw. Кроме того, существует многосимвольный литерал , который содержит более одного c-char. Одиночный литерал c-char имеет тип char, а многосимвольный литерал имеет условно-поддерживаемый тип int и значение, определяемое реализацией .

Пример:

"a" is a character literal.
"abcd" is a string literal.
"abcd" is a multicharacter literal.

Большинство компиляторов C/C++ поддерживают многосимвольные литералы. Ниже приведен пример, демонстрирующий концепцию многосимвольного литерала.

Пример 1:

Пример 2:

Выход:

Это компилируется и работает нормально, а многосимвольный литерал сохраняется как целочисленное значение (откуда берется число, вы найдете ниже). Поскольку флаг педантичного компилятора обычно передается, он выдает предупреждение обо всех многосимвольных литералах. Это предупреждение помогает указать, используем ли мы по ошибке ' вместо " . Предупреждение:

warning: multi-character character constant [-Wmultichar]

Вы можете отключить предупреждение, используя диагностику #pragma GCC, игнорируемую «-Wmultichar», непосредственно из исходного кода.

Ниже приведена важная информация о многосимвольных литералах:

1. Многосимвольные литералы отличаются от строки: многосимвольные литералы — это не то же самое, что строка или массив символов, они совершенно разные. Многосимвольные литералы — это целочисленные, а не символьные типы.

C++




#include <iostream>
#include <typeinfo>
using namespace std;
  
int main()
{
    auto a = 10;
    auto b = "a";
    auto c = "abcd";
    auto d = "abcd";
  
    // 10 is of type i or int
    cout << "type of 10 is "
      << typeid(a).name() << endl;
  
    // "a" is of type c or char
    cout << "type of "a" is "
      << typeid(b).name() << endl;
  
    // Multicharacter literals
    // "abcd" is of type i or int
    cout << "type of "abcd" is "
      << typeid(c).name() << endl;
  
    // "abcd" is of type string
    cout << "type of "abcd" is "
      << typeid(d).name() << endl;
  
    return 0;
}

Выход:

Хотя typeid() не следует использовать для указания типа, поскольку стандарт иногда гарантирует, что вы получите неверный ответ. Но здесь typeid() достаточно, чтобы указать, что Multi-character хранится как целочисленный тип, отличный от char и string.

2. Многосимвольные литералы определяются реализацией и не являются ошибкой:

Аспект семантики C++, который определяется для каждой реализации, а не указывается в стандарте для каждой реализации. Примером может служить размер int (который должен быть не менее 16 бит, но может быть и больше). По возможности избегайте поведения, определяемого реализацией.

Любой код, основанный на поведении, определяемом реализацией, гарантированно работает только на определенной платформе и/или компиляторе.
Пример:

  • размер (целое число); Это может быть 4 байта или 8 байтов в зависимости от компилятора.
  • int *p = malloc(0 * sizeof *o); Это может привести к тому, что p будет либо NULL, либо уникальным указателем (как указано в 7.20.3 стандарта C99).

C++ унаследовал многосимвольные литералы от C , а C унаследовал их от языка программирования B. Большинство компиляторов (кроме MSVC) реализуют многосимвольные литералы, как указано в B .

Дело не в том, что создатели C или C++ не знали об этом, они просто предоставили возможность разобраться с этим компиляторам.

3. Многосимвольные литералы хранятся как int, а не как char (стандарт C): Теперь вопрос в том, откуда берется целочисленное значение. В компиляторах, где int составляет 4 байта, Multi-characters хранится как 4 байта, поскольку это зависит от компилятора. Для 4-байтового многосимвольного литерала каждый символ инициализирует последовательные байты результирующего целого числа (с обратным порядком байтов, с нулевым дополнением, с правым порядком). Например, значение, преобразованное в 4 байта int для символа ASCII, как,

Здесь целые числа имеют 4 байта памяти:

Теперь наконец сохраняется ASCII первого символа слева. По сути, порядок байтов с прямым порядком байтов:

а

Затем для следующего символа целочисленное значение сдвинулось на 1 байт влево:

а б

И так далее,

а б с г

Теперь эти 4 байта представляют собой одно целое число и рассчитываются как:

"abcd" = (("a"*256 + "b")*256 + `c`)*256 + "d" = 1633837924 = 0x61626364 = "0xa0xb0xc0xd"

C++




#include <iostream>
using namespace std;
  
// Driver code
int main()
{
    cout << ""abcd" = " << "abcd" << " = " << hex
         << "abcd" << endl;
  
    cout << ""a" = " << dec << (int)"a" << " = " << hex
         << (int)"a";
  
    return 0;
}

Выход:

Если в многосимвольном литерале более 4 символов, то сохраняются только последние 4 символа и, следовательно, 'abcdefgh' == 'efgh', хотя компилятор выдаст предупреждение о переполненном литерале.

C++




#include <iostream>
using namespace std;
  
// Driver code
int main()
{
    cout << ""abcd" = " << "abcd" << endl;
    cout << ""efgh" = " << "efgh" << endl;
    cout << ""abcdefgh" = " << "abcdefgh" << endl;
    return 0;
}

Выход:

И, как и выше, если мы попытаемся сохранить многосимвольный литерал как char, тогда будет сохранен только последний символ.

C++




#include <iostream>
using namespace std;
  
// Driver code
int main()
{
    char c = "abcd";
  
    // stores as, c = " d "
    cout << c << endl;
  
    return 0;
}

Выход:

Здесь мы видим, что многосимвольный литерал, который представляет собой 4-байтовое целое число, преобразуется в 1-байтовый char и сохраняет только последний символ.

Хорошая вещь о многосимвольных литералах: поскольку многосимвольные литералы хранятся как int, их можно использовать для сравнения и в случае переключения, когда строки обычно не используются.

C++




#include <iostream>
using namespace std;
  
// Driver code
int main()
{
    int s = "abcd";
  
    switch (s) {
    case "abcd":
        cout << ("abcd" == "abcd");
  
        // s = 1633837924 and "abcd"
        // = 1633837924 so, value of
        // s is equal to "abcd"
    }
  
    return 0;
}

Выход:

Проблемы с многосимвольными литералами:

  • В C++ многосимвольные литералы поддерживаются условно. Таким образом, ваш код может не скомпилироваться.
  • Они поддерживаются, но имеют значение, определяемое реализацией . Если код работает на вашей машине нормально, это не гарантирует, что он будет работать на других машинах.
  • Кроме того, возможно, что реализация решит присвоить всем многосимвольным литералам значение 0, что нарушит ваш код.
C++ C