NUL прекращение - всегда ли это требуется? - PullRequest
1 голос
/ 17 января 2020

Меня учили всегда прерывать массивы символов. Я понимаю последствия использования функций библиотеки строк без нулевого завершения.

Является ли следующий фрагмент кода плохой практикой?

unsigned char foo[2] = { 0xFF, 0xFE }; // not null terminated

unsigned char bar[3] = { 0 };

memcpy(bar, foo, sizeof(foo));

Допустим, вы объединяете два байтовых массива. Вы не хотите нулевой терминатор в середине. Лучше объявить foo[3], включить нулевой терминатор и выполнить sizeof(foo)-1, или код выше подходит?

Ответы [ 3 ]

5 голосов
/ 17 января 2020

Нет, завершение NUL не всегда требуется.

Нулевой символ '\0' необходим для строк , в общем случае для символьных массивов.

memcpy(bar, foo, sizeof(foo)); в порядке.

3 голосов
/ 17 января 2020

Если массив не является логической строкой C -типа и не используется ни с одним API, ожидающим строки C -стиля, то вам не нужно NUL завершать, больше, чем вы делаете для массивов int. NUL Завершение требуется для логических строк C -стиля, а не для всех массивов, которые просто получаются из значений char.

Просто убедитесь, что ясно, что не строка; Вы не хотите, чтобы более поздний сопровождающий передавал что-то строковому API, потому что он выглядит логически строковым (где отсутствие NUL было просто «оптимизацией», чтобы избежать NUL путем замены строковых API на length- осведомленные API).

1 голос
/ 17 января 2020

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

  1. Всегда знать ее длину и каждый раз передавать ее.
  2. Не знать ее длину, но использовать уникальный байт терминатора (байт NUL \0), так что любой код, сканирующий строку, может идентифицировать, когда достигнут конец.

Конечно, использование терминатора NUL применимо только к строкам, и более точно, когда речь идет о функциях, которые ожидают завершение строки как NUL: все стандартные функции библиотеки C делают. Можно было бы очень хорошо написать свою собственную библиотеку с функциями, которые обрабатывают строки, не заканчивающиеся NUL.

Если вы имеете дело с массивами generi c char (или unsigned char), есть нет необходимости завершать их NUL , если вы не собираетесь использовать их в качестве строк.


В дополнение к вышесказанному терминатор NUL неявно добавлен только для объявлений с использованием строковых литералов, например:

char foo[] = "hello";
// foo actually contains 'h' 'e' 'l' 'l' 'o' '\0'

Но не при объявлении char массивов:

char foo[] = {'h', 'e', 'l', 'l', 'o'};
// foo actually contains 'h' 'e' 'l' 'l' 'o'

Объявление массивов с инициализаторами, меньшими чем размер массива приводит к заполнению остальных слотов нулями, но это другая история:

char foo[5] = {'h', 'i'};
// foo actually contains 'h' 'i' '\0' '\0' '\0'

Отвечая на ваш вопрос в комментариях:

* 1038 Отсутствие завершения NUL дает другим программистам возможность неправильно использовать переменную. Является ли возможность неправильного использования проблемой? Я собираю из ответов здесь, что это не так.

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

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