Почему C не завершает строки специальным экранированным символом завершения строки? - PullRequest
17 голосов
/ 20 июля 2009

В C строки заканчиваются нулем (\ 0), что вызывает проблемы, когда вы хотите поместить нуль в строки. Почему бы не использовать специальный экранированный символ, такой как \ $ или что-то еще?

Я полностью осознаю, насколько глуп этот вопрос, но мне было любопытно.

Ответы [ 8 ]

39 голосов
/ 20 июля 2009

Завершение с 0 имеет много тонкостей производительности, которые были очень актуальны еще в конце 60-х.

Процессоры имеют инструкции для условного перехода при тестировании на 0. На самом деле, некоторые процессоры даже имеют инструкции, которые будут повторять / копировать последовательность байтов до 0.

Если вместо этого вы использовали экранированный символ, у вас есть два тестовых ДВУХ различных байта, чтобы утвердить конец строки. Мало того, что это медленнее, но вы теряете возможность повторять по одному байту за раз, так как вам нужен упреждающий просмотр или возможность возврата.

Теперь другие языки (кашель, Паскаль, кашель) используют строки в стиле подсчета / значения. Для них допустим любой символ, но они всегда сохраняют счетчик с размером строки. Преимущество очевидно, но есть и недостатки этого метода.

С одной стороны, размер строки ограничен количеством байтов, которое занимает счет. Один байт дает вам 255 символов, два байта - 65535 и т. Д. Сегодня это может быть почти неактуально, но добавление двух байтов к каждой строке было довольно дорого.

Edit:

Я не думаю, что вопрос тупой. В наши дни языков высокого уровня с управлением памятью, невероятной мощностью процессора и неприличными объемами памяти такие решения из прошлого могут показаться бессмысленными. И действительно, они МОГУТ быть бессмысленными в наши дни, так что это хорошая вещь, чтобы допросить их.

13 голосов
/ 20 июля 2009

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

Если бы вы использовали \$ для завершения строк, какое значение байта было бы в памяти? Как бы вы включили это значение байта в строку?

Вы столкнетесь с этой проблемой, что бы вы ни делали, если будете использовать специальный символ для завершения строк. Альтернативой является использование счетных строк , при этом представление строки включает ее длину (например, BSTR ).

2 голосов
/ 20 июля 2009

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

1 голос
/ 20 июля 2009

Это вызывает проблемы, но вы можете вставить \ 0 ...

const char* hello = "Hello\0World\0\0";

Это вызывает проблему, если вы передаете это стандартным функциям библиотеки, таким как strlen, но не иначе.

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

const char* hello = "\x0BHello World";

... так делают некоторые другие языки.

0 голосов
/ 22 мая 2014

Не для преднамеренной публикации, но это все еще очень актуально для встроенного SQL.

Если вы имеете дело с двоичными данными в C, вы должны создать двоичный объект в структуре данных. Если вы можете себе это позволить, достаточно массива char. В любом случае, наверное, это не строка?

Для значений хеша / дайджеста обычно "HEX" выводит их в члены {'0', .., 'F'}. Затем они могут быть «UNHEXED» во время работы базы данных.

Для файловых операций рассмотрим двоичный поток с длиной логической записи.

Избегать их самостоятельно - это действительно безопасно, только если вы можете гарантировать кодировку. Фактически это можно увидеть в разгрузке MYSQLDUMP (SQL), где двоичные файлы должным образом экранированы для UTF-8, скажем, и схема установки «выдвигается» для загрузки и «выталкивается» впоследствии.

Я не рекомендую использовать вызов dbms для того, что должно быть библиотечной функцией, но я видел, как это было сделано. (выберите из real_escape_string ($ string)).

И есть base64, еще одна банка червей. Google UUENCODE.

Так что да, mem * работает, если ваши символы имеют фиксированную ширину.

0 голосов
/ 09 ноября 2012

Так же по историческим причинам.

Создатели std :: string в C ++ распознали этот недостаток, поэтому std :: string может содержать нулевой символ. (Но будьте осторожны , создавая std :: string с нулевым символом !)

Если вы хотите иметь C-строку (точнее, квази-C-строку) с нулевым символом, вам нужно будет создать собственную структуру.

typedef struct {
    size_t length;
    char[] data; //C99 introduced the flexible array member
} my_string;

Или вам придется каким-то другим способом отслеживать длину строки и передавать ее каждой строковой функции, которую вы пишете.

0 голосов
/ 30 июля 2009

Если стандартные библиотечные функции, такие как strlen или printf, могут (опционально) искать маркер конца строки \ 777 (в качестве альтернативы \ 000), вы можете иметь строку константных символов, содержащую \ 0s:

const char* hello = "Hello\0World\0\0\777"; 
printf("%s\n", hello); 

Кстати, если вы хотите отправить \ 0 на стандартный вывод (он же -print0), вы можете использовать:

putchar(0); 
0 голосов
/ 20 июля 2009

Нет никаких причин для того, чтобы нулевой символ был частью строки, кроме как в качестве терминатора; он не имеет графического представления, поэтому вы не увидите его и не будете действовать как управляющий символ. Что касается текста, это настолько внеполосное значение, сколько вы можете получить, не используя другое представление (например, многобайтовое значение, например 0xFFFF).

Чтобы немного перефразировать вопрос Майкла, как вы ожидаете, что "Hello \ 0World \ 0" будет обработан?

...