Каковы некоторые недостатки использования строк в стиле C? - PullRequest
8 голосов
/ 23 ноября 2008

Я знаю, что переполнения буфера представляют собой одну потенциальную опасность для использования строк в стиле C (массив символов) Если я знаю, что мои данные поместятся в моем буфере, можно ли их использовать в любом случае? Есть ли другие недостатки, присущие строкам в стиле C, о которых мне нужно знать?

РЕДАКТИРОВАТЬ: Вот пример, близкий к тому, над чем я работаю:

char buffer[1024];
char * line = NULL;
while ((line = fgets(fp)) != NULL) { // this won't compile, but that's not the issue
    // parse one line of command output here.
}

Этот код получает данные из указателя FILE, который был создан с помощью команды popen("df"). Я пытаюсь запустить команды Linux и проанализировать их вывод, чтобы получить информацию об операционной системе. Есть ли что-то неправильное (или опасное) при установке буфера на произвольный размер таким образом?

Ответы [ 16 ]

20 голосов
/ 24 ноября 2008

Есть несколько недостатков для строк C:

  1. Получение длины - относительно дорогая операция.
  2. Запрещено использование встроенных нулевых символов.
  3. Подпись символов определяется реализацией.
  4. Набор символов определяется реализацией.
  5. Размер типа char определяется реализацией.
  6. Необходимо отслеживать отдельно, как распределяется каждая строка и как она должна быть свободна или даже если она вообще нужна.
  7. Нет способа ссылаться на фрагмент строки как на другую строку.
  8. Строки не являются неизменяемыми, то есть они должны синхронизироваться отдельно.
  9. Строки не могут быть изменены во время компиляции.
  10. Случаи переключения не могут быть строками.
  11. Препроцессор C не распознает строки в выражениях.
  12. Невозможно передать строки в качестве аргументов шаблона (C ++).
16 голосов
/ 23 ноября 2008

В строках C отсутствуют следующие аспекты своих аналогов в C ++:

  • Автоматическое управление памятью: вы должны выделить и освободить их память вручную.
  • Дополнительная емкость для эффективности объединения: строки C ++ часто имеют емкость, превышающую их размер. Это позволяет увеличить размер без большого перераспределения.
  • Нет встроенных NUL: по определению символ NUL заканчивает строку C; Строка C ++ содержит внутренний счетчик размеров, поэтому им не нужно специальное значение для обозначения конца.
  • Разумные операторы сравнения и присваивания: даже если разрешено сравнение строковых указателей C, это почти всегда , а не , что предполагалось. Точно так же назначение строковых указателей C (или передача их функциям) создает неоднозначности владения.
14 голосов
/ 23 ноября 2008

Отсутствие длины, доступной в постоянном времени, является серьезной нагрузкой во многих приложениях.

8 голосов
/ 24 ноября 2008

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

Если преждевременная оптимизация является корнем всего зла, магические числа являются основой.

7 голосов
/ 23 ноября 2008

Управление памятью и т. Д., Необходимые для увеличения строки (массив символов), при необходимости, скучно изобретать заново.

6 голосов
/ 23 ноября 2008

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

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

При чтении ввода из файла используйте функцию, которая позволяет указать максимальное количество байтов для чтения. В OSX и Linux fgets () фактически определяется как char *fgets(char *s, int size, FILE *stream);, поэтому его можно было бы безопасно использовать в этих системах.

6 голосов
/ 23 ноября 2008

Нет способа встроить NUL-символы (если они вам нужны для чего-либо) в строки стиля C.

3 голосов
/ 23 ноября 2008

В вашем конкретном случае опасна не c-строка, а считывание неопределенного объема данных в буфер фиксированного размера. Никогда не используйте get (char *), например.

Хотя, глядя на ваш пример, он выглядит не совсем корректно - попробуйте это:

char buffer[1024];
char * line = NULL;
while ((line = fgets(buffer, sizeof(buffer), fp)) != NULL) {
    // parse one line of command output here.
}

Это совершенно безопасное использование c-строк, хотя вам придется столкнуться с возможностью того, что line не содержит всю строку, а скорее урезан до 1023 символов (плюс нулевой терминатор). 1007 *

3 голосов
/ 23 ноября 2008

Проблемы кодировки символов проявляются, когда у вас есть массив байтов вместо строки символов.

2 голосов
/ 24 ноября 2008

Нет поддержки Юникода в наши дни.

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