Как напечатать строку, в которую __FILE__ правильно расширяется? - PullRequest
10 голосов
/ 20 июля 2010

Рассмотрим эту программу:

#include <stdio.h>
int main() {
    printf("%s\n", __FILE__);
    return 0;
}

В зависимости от имени файла, эта программа работает - или нет. Проблема, с которой я сталкиваюсь, заключается в том, что я хотел бы напечатать имя текущего файла безопасным для кодирования способом. Однако, если файл содержит забавные символы, которые не могут быть представлены в текущей кодовой странице, компилятор выдает предупреждение (справедливо):

?????????.c(3) : warning C4566: character represented by universal-character-name '\u043F' cannot be represented in the current code page (1252)

Как мне справиться с этим? Я хотел бы сохранить строку, заданную __FILE__, например, в UTF-16, чтобы я мог правильно распечатать его на любой другой системе во время выполнения (путем преобразования сохраненного представления UTF-16 во все, что использует система времени выполнения). Для этого мне нужно знать:

  1. Какая кодировка используется для строки, заданной __FILE__? Кажется, что, по крайней мере в Windows, используется текущая системная кодовая страница (в моем случае, Windows-1252) - но это только предположение. Это правда?
  2. Как я могу сохранить UTF-8 (или UTF-16) представление этой строки в моем исходном коде во время сборки?

Мой реальный пример использования: у меня есть макрос, который отслеживает текущее выполнение программы, записывая информацию о текущем исходном коде / номере строки в файл. Это выглядит так:

struct LogFile {
    // Write message to file. The file should contain the UTF-8 encoded data!
    void writeMessage( const std::string &msg );
};

// Global function which returns a pointer to the 'active' log file.
LogFile *activeLogFile();

#define TRACE_BEACON activeLogFile()->write( __FILE__ );

Это прерывается, если текущий исходный файл имеет имя, содержащее символы, которые не могут быть представлены текущей кодовой страницей.

Ответы [ 5 ]

11 голосов
/ 20 июля 2010

Использование может использовать оператор вставки токена, например:

#define WIDEN2(x) L ## x
#define WIDEN(x) WIDEN2(x)
#define WFILE WIDEN(__FILE__)

int main() {
    wprintf("%s\n", WFILE);
    return 0;
}
1 голос
/ 20 июля 2010

__FILE__ всегда будет расширяться до символьной строки литерала , таким образом, по сути, он будет совместим с char const*.Это означает, что реализация компилятора не имеет другого выбора, кроме как использовать raw байтовое представление имени исходного файла, как оно представляется во время компиляции.

Является ли это чем-то разумным втекущая локаль или нет не имеет значения, у вас может быть имя исходного файла, которое содержит в основном мусор, если ваша система времени исполнения и компилятор принимают его как действительное имя файла.

Если вы, какпользователь, у вас будет другая локаль с другой кодировкой, чем в вашей файловой системе, вы увидите много ????или аналогично.

Но , если обе ваши локали согласуются с кодировкой, должно быть достаточно простого printf, и ваш терминал (или все, что вы используете для просмотра вывода) должен быть в состоянииправильно печатайте символы.

Итак, короткий ответ: он будет работать только в том случае, если ваша система соответствует кодировке.В противном случае вам не повезло, так как угадать кодировки довольно сложно.

0 голосов
/ 20 июля 2010

В MSVC вы можете включить Unicode и получить строки в кодировке UTF-16.Это где-то в свойствах проекта.Кроме того, вы должны просто использовать wcout / cout, а не printf / wprintf.Windows существовал Unicode до появления Unicode, поэтому у них была настраиваемая многобайтовая кодировка символов, которая используется по умолчанию.Тем не менее, Windows поддерживает UTF16 - это, например, C #.

#include <iostream>

int main() {
    std::wcout << __WFILE__;
}
0 голосов
/ 20 июля 2010

Лучшее решение - использовать исходные имена файлов в наборе символов переносимого имени файла [A-Za-z0-9._-].Поскольку Windows не поддерживает UTF-8, произвольные символы, не входящие в ASCII, не могут быть представлены в обычных строках вне зависимости от вашего настроенного локального языка.

gcc, вероятно, не заботится;он обрабатывает все имена файлов как 8-битные строки и поэтому, если имя файла доступно для gcc, его имя будет представимым.(Я знаю, что cygwin по умолчанию предоставляет среду UTF-8, а современный * nix обычно будет UTF-8.) Для MSVC вы можете использовать препроцессор, чтобы добавить L к расширению __FILE__ и использовать %ls чтобы отформатировать.

0 голосов
/ 20 июля 2010

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

Что касается того, как с этим справиться, как изменить код, например:

#define TRACE_BEACON activeLogFile()->write( FixThisString(__FILE__ )); 

std::string FixThisString(wchar_t* bad_string) { .....}

(Внедрение FixThisString оставлено в качестве упражнения для студента.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...