Что такое кодировка argv?

Мне не ясно, какие кодировки используются в C argv . В частности, меня интересует следующий сценарий:

  • Пользователь использует языковой стандарт L1 для создания файла, имя которого, N , содержит символы, отличные от ASCII
  • Позже пользователь использует языковой стандарт L2 для завершения имени этого файла в командной строке, которое вводится в программу P в качестве аргумента командной строки

Какую последовательность байтов P видит в командной строке?

Я заметил, что на Linux, создание имени файла в языковом стандарте UTF-8 и последующее его завершение (например) в языковом стандарте zw_TW.big5 , похоже, приводит к тому, что моя программа P загружается в UTF-8, а не в Big5 ]. Однако в OS X та же серия действий приводит к тому, что моя программа P получает имя файла в кодировке Big5 .

Вот то, что, как мне кажется, происходит до сих пор (долго, и я, вероятно, ошибаюсь и необходимо исправить):

Windows

Имена файлов хранятся на диске в некотором формате 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

История с дисковым хранилищем такая же, насколько и Я знаю. OS X хранит имена файлов в формате Unicode.

С терминалом Unicode, я думаю, происходит то, что терминал создает командную строку в буфере Unicode. Таким образом, когда вы завершаете табуляцию, он копирует имя файла как имя файла Unicode в этот буфер.

Когда вы запускаете команду, этот буфер Unicode преобразуется в текущую локаль, L2, и передается в программу через argv , и программа может декодировать argv с текущей локалью в Unicode для отображения.

Linux

В 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 , чтобы изменить локаль.

38
задан phuclv 21 July 2016 в 11:42
поделиться