#c #memory #binary #wchar-t
Вопрос:
#include <stdio.h> wchar_t wc = L' 459'; printf("%d", wc); //result : 32
Я знаю, что «пробел» — это «десятичное число 32» в таблице кодов ASCII.
Чего я не понимаю, так это того, насколько я знаю, что если для переменной недостаточно места для хранения значения, значение будет «последними цифрами» исходного значения.
Например, если я помещу двоичное значение «1100 1001 0011 0110» в однобайтовую переменную, это будет «0011 0110», который является «последним байтом» исходного двоичного значения.
Но приведенный выше код показывает «первый байт» исходного значения.
Я хотел бы знать, что происходит на уровне памяти, когда я выполняю приведенный выше код.
Комментарии:
1. Согласно спецификации C, » Значение широкой символьной константы, содержащей более одного многобайтового символа или одного многобайтового символа, который сопоставляется нескольким элементам расширенного набора символов выполнения или содержит многобайтовый символ или escape-последовательность, не представленные в расширенном наборе символов выполнения, определяется реализацией».
2. Например, Microsoft MSVC (cl) и GNU GCC (gcc)
wc
имеют разные значения. MSVC устанавливает его вL' '
значение, а GCC устанавливает его вL'9'
значение . Оба компилятора выдадут предупреждение об усечении, если вы установите уровень предупреждения достаточно высоким.3.
wchar_t
составляет 4 байта в Linux и 2 байта в Windows. В любом случаеwchar_t wc = L' 459'
это недопустимо. Опишите, над какой системой вы работаете и какова ваша цель.4. @Barmak Shemirani Он запускается без какого-либо предупреждения на VS2019. Моя цель — «узнать, как это действительно работает на уровне памяти». Насколько я узнал, в моем коде нет проблем, потому что «wchar_t» имеет тип «без подписи короткий» в VS, а буквенный префикс символов » L «представляет значение » тип wchar_t», поэтому я не вижу никаких проблем в своем коде.
Ответ №1:
_int64 x = 0x0041'0042'0043'0044ULL; printf("6llxn", x); //prints 0041004200430044 wchar_t wc; wc = x; printf("Xn", wc); //prints 0044 as you expect wc = L'x0041x0042x0043x0044'; //prints 0041, uses the first character printf("Xn", wc);
Если вы присваиваете слишком большое целочисленное значение, компилятор принимает максимальное значение 0x0044
, которое помещается в 2 байта.
Если вы попытаетесь назначить несколько элементов одному элементу, компилятор выберет первый элемент 0x0041
, который подходит. L'x'
это означает быть одним широким персонажем.
VS2019 выдаст предупреждение для wchar_t wc = L' 459'
, если уровень предупреждения не установлен ниже 3, но это не рекомендуется. Используйте предупреждение уровня 3 или выше.
wchar_t
является примитивным типом, а не typedef
для unsigned short
, но оба они составляют 2 байта в Windows (4 байта в Linux).
Обратите внимание, что 'abcd'
это 4 байта. L
Префикс указывает 2 байта на элемент (в Windows), то L'abcd'
есть 8 байт.
Чтобы увидеть , что находится внутри wc
, давайте посмотрим на символ Юникода L'X'
, который имеет кодировку UTF-16 0x0058
(аналогично значениям ASCII до 128).
#include <stdlib.h> #include <stdio.h> #include <string.h> int main(void) { wchar_t wc = L'X'; wprintf(L"%cn", wc); char buf[256]; memcpy(buf, amp;wc, 2); for (int i = 0; i < 2; i ) printf("X ", buf[i] amp; 0xff); printf("n"); return 0; }
Результат будет таким 58 00
. Это не 00 58
потому, что Windows работает в системах с малым числом пользователей, и байты переворачиваются.
Еще одна странная вещь заключается в том, что UTF16 использует 4 байта для некоторых кодовых точек. Таким образом, вы получите предупреждение для этой строки:
wchar_t wc = L'😀';
Вместо этого вы хотите использовать строку:
wchar_t *wstr = L"😀"; ::MessageBoxW(0, wstr, 0, 0); //console may not display this correctly
Эта строка будет состоять из 6 байтов (2 элемента нулевой завершающий символ).
Комментарии:
1. Я не могу полностью понять, что означает этот ответ, и я все еще не могу понять, что происходит с моим кодом, но в любом случае спасибо за ответ. Если бы вы могли подробно описать точный процесс обработки данных на уровне памяти при выполнении ‘wchar_t wc = L’ 459′, это было бы очень полезно.
2.
L' 459'
это 8 байт, это не вписывается вwc
то, что составляет 2 байта. Компилятор игнорирует (459), он просто использует первый символwc = L' ';
, запускающий этот код:wprintf(L"[%c] X", wc, wc)
результатом будет"[ ] 0020"
(пустое пространство и его значение ASCII). — Ты о чем думаешьconst wchar_t *str = L"1234"
?3. Но когда я делаю «wchar_t wc = ‘459’», результатом «printf(«%d», wc)» является «13625», что является «последними» 2 байтами исходного значения 4 байта. Чего я не понимаю, так это почему printf L» 459″ показывает часть «пробел», в то время как printf » 459 «показывает часть «59». Они совершенно противоположны друг другу.
4. wchar_t wc = ‘459’ И printf с использованием %d = показывает ‘13625’. wchar_t wc = L’ 459′ И printf с использованием %d = показывает «32». Я хотел бы знать разницу в данных памяти между » 459 » и «459».
5.
13625
то есть0x3539
, это соответствует значениям ASCII для последних 2 символов в' 459'
. Присвоение' 459'
wchar_t
недопустимо. Компилятор обрабатывает' 459'
как 4-байтовое целое число, затем пытается сопоставить его сwchar_t
тем, как описано в ответе.