что означает const void* в memmove?

Второй аргумент в прототипах для memmove/memcpy/strcpy аналогичен: Например:

void *memmove(void *dest, const void *src, size_t n); //const void*
char *strcpy(char *dest, const char *src); //const char*

Но очевидно, что если dest и src перекрываются, то содержимое src будет изменено, нарушая условие const void/char *?


person Alcott    schedule 16.09.2011    source источник


Ответы (4)


const void* означает, что реферанд не будет изменен через этот указатель.

Если есть другие неконстантные указатели на тот же объект (также известный как «псевдоним»), то, конечно, он все равно может быть изменен через них. В описанном вами сценарии этот другой указатель — dest.

Кстати, в случае с strcpy поведение undefined, если регионы перекрываются, а в C99 сигнатура char *strcpy(char * restrict s1, const char * restrict s2);. Но для memmove с псевдонимами все в порядке. Предоставляя ему перекрывающиеся регионы, вы дали ему «разрешение» изменять регион dest, и он это сделает.

person Steve Jessop    schedule 16.09.2011
comment
Вы имеете в виду, что если я не могу убедиться, перекрываются ли dest и src или нет, мне лучше не использовать strcpy, верно? - person Alcott; 16.09.2011
comment
@Alcott: это верно. Что вы, скорее всего, увидите на практике, так это то, что если ваши регионы перекрываются с dest < src, тогда это будет работать. Если они перекрываются с src < dest, то нулевой байт в конце src будет перезаписан до того, как он будет прочитан, а затем функция войдет в бесконечный цикл, очищающий память, пока не произойдет что-то терминальное. Но вы не можете полагаться ни на одно из этих поведений. - person Steve Jessop; 16.09.2011

Аргумент помечен const void *, чтобы указать, что memmove никогда не будет изменять память, на которую указывает src, используя этот указатель. Если происходит перекрытие, память модифицируется с помощью указателя dest, а не указателя src, поэтому гарантия не нарушается.

person Praetorian    schedule 16.09.2011

Это означает, что memmove гарантирует, что он не будет напрямую изменять память, на которую указывает src.

Конечно, если два блока перекрываются, memmove изменит так называемую "константную" память. const — это контракт, прикрепленный к имени. Невозможно сделать фактическую память доступной только для чтения.

person cnicutar    schedule 16.09.2011
comment
@Praetorian Я часто не знаю, о чем говорю, но мне нравятся комментарии, чтобы я мог учиться :-) - person cnicutar; 16.09.2011

Как указано выше, memove не будет изменять содержимое памяти через указатель «src», а будет через указатель «dest».

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

Если оба указателя указывают на перекрывающуюся область памяти, то может произойти что угодно, поскольку не определено, будет ли копия начинаться с «src» и увеличиваться или начинаться с «src + n» и уменьшаться.

person John Beckett    schedule 16.09.2011
comment
извините за повторный ответ, который я отправил в то же время, когда вышеизложенное было отредактировано - person John Beckett; 16.09.2011
comment
такие вещи случаются все время, это не проблема. Обычно в ответах есть тонкие различия, даже если они по существу одинаковы, и часто весьма полезно иметь несколько объяснений одного и того же вопроса — один читатель лучше поймет одно из них, кто-то другой поймет другое. - person Steve Jessop; 16.09.2011