Возврат каретки + перевод строки в необработанных строковых литералах?

Рассмотрим файл C++ с окончаниями строк UNIX (т.е. '\x0a' вместо "\x0d\x0a") и включает следующий необработанный строковый литерал:

const char foo[] = R"(hello^M
)";

(где ^M фактический байт 0x0d (т.е. возврат каретки)).

Каким должен быть результат последующего сравнения строк (с учетом стандартного определения необработанных строковых литералов)?

strcmp("hello\r\n", foo);

Должны ли строки сравниваться с равными или нет? (т.е. 0 или же !=0?)

С GCC 4.8 (на Fedora 19) они сравниваются неравно.

Это ошибка или функция в GCC?

1 ответ

Решение

Что касается стандарта, вы можете использовать только члены базового исходного набора символов в строковых литералах (и в других местах программы). То, как физическое представление программы отображается на базовый исходный набор символов, определяется реализацией.

g ++, очевидно, считает, что ASCII \x0a, ASCII \x0d и ASCII \x0d\x0a - все допустимые представления члена базового исходного набора символов, называемого "новой строкой". Что вполне разумно, учитывая, что желательно, чтобы исходный код, передаваемый между компьютерами Windows, Unix и Mac OS X Classic, сохранял свое значение.

Необработанные строковые литералы не являются полностью необработанными, поскольку они поступают в вашу программу через компилятор, который считывает и интерпретирует входные файлы C++. Перед strcmp'ing 2 строки вы можете проверить размер вашей необработанной строки - он будет отличаться от ожидаемого на количество символов ^M (\x0d).

Вы можете прибегнуть к чтению данных как двоичному, например (пример двоичного чтения / w):

std::ifstream infile ("test.txt", std::ifstream::binary);
infile.seekg (0,infile.end);
long size = infile.tellg();
infile.seekg (0);
char* buffer = new char[size];
infile.read (buffer,size);

Или вы можете настоять на использовании необработанных литералов, но с некоторыми уловками - замените все "плохие" символы некоторыми другими символами в своем литерале, а затем выполните обратную замену, когда вы используете этот литерал, например:

... all includes ...

std::string str = R"(hello|
)";

int main()
{
  std::replace(str.begin(), str.end(), '|', '\015');
  std::cout << strcmp("hello\r\n", str.data()) << std::endl;
}
Другие вопросы по тегам