2010-09-20 4 views
70

Нужно ли мне лечить случаи, когда я actully нечего перемещать/копировать с memmove()/memcpy() как крайние случаиМогу ли я вызвать memcpy() и memmove() с «числом байтов», установленным на ноль?

int numberOfBytes = ... 
if(numberOfBytes != 0) { 
    memmove(dest, source, numberOfBytes); 
} 

или я должен просто позвонить функцию без проверки

int numberOfBytes = ... 
memmove(dest, source, numberOfBytes); 

ли проверка в первом фрагменте необходимо?

+6

вопрос напоминает мне немного проверки нулевых указателей на такие функции, как free. Не нужно, но я бы добавил комментарий, чтобы показать, что вы об этом подумали. – Toad

+10

@Toad: Какая цель это служит, кроме как загромождать код?Читая чей-то код, мне не нужно знать, что первоначальный программист «думал о том, чтобы делать эту операцию, которая на самом деле не нужна, а потому, что это не нужно, я этого не делал». Если я вижу, что указатель освобожден, я * знаю *, это разрешено быть нулевым, поэтому мне не нужно знать мысли первоначального программиста по теме «должен ли я проверять значение null». И то же самое касается копирования 0 байтов с 'memcpy' – jalf

+5

@jalf: тот факт, что это вопрос о stackoverflow, заставляет его сомневаться. Поэтому добавление комментария может не помочь вам, но может помочь кому-то с меньшими знаниями. – Toad

ответ

102

От стандарта C99 (7.21.1/2):

Где аргумент объявлен как size_t n задает длину массива для функции, n может иметь нулевое значение при вызове, что функция. Если явно не указано в противном случае в описании конкретной функции в этом подпункте, аргументы указателя на такой вызов все равно должны иметь действительные значения, как описано в 7.1.4. При таком вызове функция , которая находит символ, не находит никакого вхождения, функция, которая сравнивает две последовательности символов , возвращает ноль, а функция, которая копирует символы, копирует нулевые символы .

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

+0

Будет ли указатель считаться «действительным» для целей такой функции, если он указывает на местоположение, следующее за последним элементом массива? Такой указатель не может быть законно отсрочен, но можно смело делать некоторые другие вещи-указатели, такие как вычитание из него. – supercat

+0

@supercat: да, указатель, указывающий один за концом массива, действителен для арифметики указателя с другими указателями внутри (или один за концом) этого массива, но не является неразрешимым. –

+0

@MikeSeymour: не следует ли ссылаться на противоположный ответ: проверка необходима, и вы не можете пройти нуль с нулевыми указателями? – neverhoodboy

2

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

+0

Не обязательно. Очень частое использование - это вставка и удаление из массивов, которые могут не быть массивами 'char'. Любое использование массива может иметь нулевое перемещение как естественный случай, и неплохо не иметь специального случая. –

12

Документация memmove и memcpy говорит, что это:

Функция не проверяет для любого завершающего нулевого символа в источник - он всегда копирует точно Num байты.

opengroupdocumentation говорит в основном то же самое.

Таким образом, учитывая, что он копирует «ровно NUM байт», он будет копировать нулевые байты, когда num = 0, и, таким образом, оно не должно быть необходимым, чтобы рассматривать это как частный случай.

+1

Если он всегда копирует точно * num * байты, у него не возникнет проблем с копированием точно 0 байтов. :) –

+1

@qrdl: Это так, он отвечает на вопрос «мне нужно лечить' num = 0' как частный случай? ». – You

+1

ОП задал вопрос о краевом условии, поэтому предоставление ответа в общем случае неприемлемо. После редактирования появилось бит 'num = 0'. – qrdl

5

Как указано в @You, стандарт указывает, что memcpy и memmove должны обрабатывать этот случай без проблем; поскольку они обычно реализуются так или иначе, как и у

void *memcpy(void *_dst, const void *_src, size_t len) 
{ 
    unsigned char *dst = _dst; 
    const unsigned char *src = _src; 
    while(len-- > 0) 
     *dst++ = *src++; 
    return _dst; 
} 

у вас не должно быть никаких нарушений производительности, кроме вызова функции; если компилятор поддерживает встроенные/встроенные функции для таких функций, дополнительная проверка может даже сделать код на микро-бит-бит медленнее, так как проверка уже выполняется в то время.

+0

Я бы подумал, что эта функция, вероятно, сделана в сборке, где вы можете оптимизировать трансакции памяти намного лучше, чем в c – Toad

+0

* «как-то вроде» * :) На самом деле почти все реализации, которые я видел, собраны и пытаются скопировать большую часть биты, использующие размер родного слова (например, uint32_t на x86), но это не меняет сути ответа: это цикл * while *, который не требует больших вычислений перед запуском, поэтому проверка уже выполнена. –

+5

-1, типичная реализация не имеет отношения к тому, является ли допустимым C для вызова этих функций (которые, возможно, даже не реализованы как C-функции) с нулевым аргументом. –

 Смежные вопросы

  • Нет связанных вопросов^_^