Мне не ясно, какие кодировки используются в C argv
. В частности, меня интересует следующий сценарий:
N
, содержит символы, отличные от ASCII Какую последовательность байтов P видит в командной строке?
Я заметил, что на Linux, создание имени файла в языковом стандарте UTF-8 и последующее его завершение (например) в языковом стандарте zw_TW.big5
, похоже, приводит к тому, что моя программа P загружается в UTF-8, а не в Big5
]. Однако в OS X та же серия действий приводит к тому, что моя программа P получает имя файла в кодировке Big5
.
Вот то, что, как мне кажется, происходит до сих пор (долго, и я, вероятно, ошибаюсь и необходимо исправить):
Имена файлов хранятся на диске в некотором формате Unicode. Итак, Windows берет имя N
, преобразует L1 (текущая кодовая страница) в версию Unicode N
, которую мы назовем N1
, и сохраняет N1
на диске.
То, что я предполагаю , происходит, так это то, что при закрытии табуляции позже, имя N1
преобразуется в языковой стандарт L2 (новая текущая кодовая страница) для отображения. Если повезет, это даст исходное имя N
- но это не будет так, если N
содержит символы, не представленные в L2. Мы называем новое имя N2
.
Когда пользователь фактически нажимает клавишу ввода для запуска P с этим аргументом, имя N2
конвертируется обратно в Unicode, давая N1
снова. Этот N1
теперь доступен программе в формате UCS2 через GetCommandLineW
/ wmain
/ tmain
, но пользователям GetCommandLine
/ main
увидит имя N2
в текущей локали (кодовой странице).
История с дисковым хранилищем такая же, насколько и Я знаю. OS X хранит имена файлов в формате Unicode.
С терминалом Unicode, я думаю, происходит то, что терминал создает командную строку в буфере Unicode. Таким образом, когда вы завершаете табуляцию, он копирует имя файла как имя файла Unicode в этот буфер.
Когда вы запускаете команду, этот буфер Unicode преобразуется в текущую локаль, L2, и передается в программу через argv
, и программа может декодировать argv с текущей локалью в Unicode для отображения.
В Linux все по-другому, и я очень запутался в том, что происходит. Linux хранит имена файлов в виде байтовых строк , а не в Unicode. Итак, если вы создаете файл с именем N
в локали L1, то N
в виде байтовой строки - это то, что хранится на диске.
Когда я позже запускаю терминал и пытаюсь заполнить имя табуляцией, я не уверен, что происходит. Мне кажется, что командная строка построена как байтовый буфер, а имя файла в виде байтовой строки просто добавлено в этот буфер. Я предполагаю, что когда вы вводите стандартный символ, он на лету кодируется в байты, которые добавляются к этому буферу.
Когда вы запускаете программу, я думаю, что буфер отправляется непосредственно в argv
. Какая кодировка у argv
? Похоже, что любые символы, которые вы вводили в командной строке в локали L2, будут в кодировке L2, но имя файла будет в кодировке L1 . Итак, argv
содержит смесь двух кодировок!
I ' Мне бы очень понравилось, если бы кто-нибудь мог сообщить мне, что здесь происходит. Все, что у меня есть на данный момент, - это полугадания и предположения, и они действительно не подходят друг другу. Я действительно хотел бы, чтобы argv
был закодирован в текущей кодовой странице (Windows) или текущей локали (Linux / OS X), но, похоже, это не так. ..
Вот простая программа-кандидат P, которая позволяет вам наблюдать за кодировками самостоятельно:
#include <stdio.h>
int main(int argc, char **argv)
{
if (argc < 2) {
printf("Not enough arguments\n");
return 1;
}
int len = 0;
for (char *c = argv[1]; *c; c++, len++) {
printf("%d ", (int)(*c));
}
printf("\nLength: %d\n", len);
return 0;
}
Вы можете использовать locale -a
для просмотра доступных локалей и использовать экспорт LC_ALL = my_encoding
, чтобы изменить локаль.