Как безопасно объявить 16-битный строковый литерал в C?

Я знаю, что уже есть стандартный метод с префиксом L:

wchar_t *test_literal = L"Test";

Проблема в том, что wchar_t не обязательно будет 16-битным, но для моего проекта мне нужен 16-битный wchar_t. Я также хотел бы избежать требования передачи -fshort-wchar.

Итак, есть ли какой-либо префикс для C (не C++), который позволит мне объявить строковый литерал UTF-16?


person Community    schedule 02.06.2018    source источник
comment
Мне нужен 16-битный wchar_t — зачем?   -  person melpomene    schedule 02.06.2018
comment
@melpomene 1. Я на встроенной платформе. 2. Это часть Windows-подобного API.   -  person    schedule 02.06.2018
comment
Что не так с -fshort-wchar?   -  person melpomene    schedule 02.06.2018
comment
@melpomene Префикс будет частью файла заголовка, включенного в мою библиотеку и приложение. Я не хочу заставлять приложение использовать -fshort-wchar.   -  person    schedule 02.06.2018
comment
Это похоже на какую-то проблему XY.   -  person melpomene    schedule 02.06.2018
comment
Вам лучше инициализировать их как есть и предоставить функцию преобразования для преобразования литерала в массив любого типа, который вы используете для конкретного представления символов UTF-16 (short, int16_t) или чего-то еще. Это упростит работу в системах, где wchar_t и UTF-16 не совпадают.   -  person Peter    schedule 02.06.2018
comment
@melpomene Да ... Я хочу иметь тип WCHAR и макрос TEXT, как в Windows.   -  person    schedule 02.06.2018
comment
Но почему? Какую общую проблему вы пытаетесь решить здесь?   -  person melpomene    schedule 02.06.2018
comment
@melpomene Я хочу иметь возможность переключаться между ASCII и Unicode. Итак, я бы сделал макрос TEXT, который принимал литерал в качестве параметра, и в зависимости от того, была ли библиотека построена для ASCII или Unicode, при необходимости добавлял префикс литерала, чтобы превратить его в wchar_t.   -  person    schedule 02.06.2018
comment
Да, но почему?   -  person melpomene    schedule 02.06.2018
comment
В противном случае я должен использовать уродливый массив. wchar_t str[4] = { 'T', 'e', 's', 't' }   -  person    schedule 02.06.2018
comment
Нет, вы можете просто предоставить один интерфейс UTF-8. Зачем заставлять приложения перекомпилировать, если они хотят использовать Unicode?   -  person melpomene    schedule 02.06.2018
comment
Давайте продолжим это обсуждение в чате.   -  person    schedule 02.06.2018


Ответы (2)


Итак, есть ли какой-либо префикс для C (не C++), который позволит мне объявить строковый литерал UTF-16?

Почти, но не совсем. C2011 предлагает вам следующие варианты:

  • литералы символьных строк (элементы типа char) - без префикса. Пример: "Test"
  • Строковые литералы UTF-8 (элементы типа char) - префикс 'u8'. Пример: u8"Test"
  • wide string literals of three flavors:
    • wchar_t elements - 'L' prefix. Example: L"Test"
    • Элементы char16_t — префикс 'u'. Пример: u"Test"
    • char32_t элементы - префикс 'U'. Пример: U"Test"

Обратите внимание, однако, что, хотя вы можете объявить широкий строковый литерал, содержащий элементы типа char16_t, стандарт не гарантирует, что для них будет использоваться кодировка UTF-16, а также не предъявляет каких-либо конкретных требований к тому, какие символы не входят в язык. базовый набор символов должен быть включен в набор символов выполнения. Однако вы можете протестировать первое во время компиляции: если char16_t представляет символы в кодировке UTF-16 в данной соответствующей реализации, то эта реализация определит макрос с __STDC_UTFchar16_t_ по 1.

Также обратите внимание, что вам необходимо включить (C) заголовок uchar.h, чтобы использовать имя типа char16_t, но синтаксис u"..." для литералов от этого не зависит. Будьте осторожны, так как это имя заголовка конфликтует с именем, используемым интерфейсом C Международных компонентов для Unicode, относительно широко используемого пакета для поддержки Unicode.

Наконец, имейте в виду, что многое из этого было новым в версии C2011. Чтобы использовать его, вам нужна соответствующая реализация C2011. Они, безусловно, доступны, но есть и множество реализаций, которые соответствуют только более ранним стандартам или даже не соответствуют ни одному из них. Стандарт C99 и более ранние версии не предоставляют синтаксиса строкового литерала, гарантирующего 16-битные элементы.

person John Bollinger    schedule 02.06.2018

Вам нужен 16-битный wchar_t, но это вне вашего контроля. Если компилятор говорит, что он 32-битный, значит, он 32-битный, и не имеет значения, что вы хотите или что вам нужно.

Строковые классы являются шаблонными. Вы всегда можете использовать шаблон для создания класса шаблона с 16-битными символами. Я лично попытался бы удалить любую обработку Unicode, отличную от UTF-8.

Альтернативным методом является умный #ifdef, который выдаст ошибку времени компиляции, если wchar_t не 16-битный, и решит проблему, когда вам действительно нужно ее решить.

person gnasher729    schedule 02.06.2018
comment
Шаблонные строковые классы? В Си? - person melpomene; 02.06.2018
comment
Думаю, мне придется использовать #ifdef и -fshort-wchar. Это единственный метод, который гарантированно работает. - person ; 02.06.2018
comment
Действительно, не гарантируется, что wchar_t будет 16-битным — оно может быть больше или меньше, — но C2011 действительно имеет char16_t, что равно 16 битам, и синтаксис для расширенных строковых литералов, содержащих элементы тот тип. - person John Bollinger; 02.06.2018
comment
@JohnBollinger Проблема в том, что не все компиляторы пока поддерживают C2011 (и я думаю, особенно встроенные наборы инструментов). - person ; 02.06.2018
comment
Это совершенно верно, @MarkYisri, но C2011 является текущим стандартом C, и он уже не такой уж новый. Хотя мы можем и должны признать, что некоторые релевантные реализации не соответствуют этой версии, вопросы, которые не определены иным образом, должны интерпретироваться в первую очередь в свете текущей версии языка. - person John Bollinger; 02.06.2018