2017-02-11 11 views
5

Например, следующая функция правовой:Является ли законным использовать memcpy с структурой назначения с постоянными членами?

struct two_int { 
    const int a, b; 
} 

void copy_two(const two_int *src, two_int *dest) { 
    memcpy(dest, src, sizeof(two_int)); 
} 

Похоже, что по крайней мере некоторые типы модификаций постоянных заданных значений не допускается, но это мне не ясно, если это квалифицируется.

Если ответ «это не допускается, в общем», я также интересно, о частном случае, когда dest вновь выделенной памяти с malloc (и, следовательно, еще не назначен никакой ценности), такие как:

two_int s = {.a = 1, .b = 2}; 
two_int *d = malloc(sizeof(two_int)); 
copy_two(&s, d); 

Update: Похоже, кажется, ответил утвердительно (это нормально) для случая новопостроенных malloc «й структуры последнего вопроса, но оригинал, более общий вопрос все еще стоит , Я думаю.

+4

№ Пытается изменить постоянные переменные * где угодно * это * неопределенное поведение *. –

+2

Это означает, что 'two_int' может _never_ быть распределенным через' malloc' или иначе динамически, не так ли? Поскольку вы не можете передать какую-либо информацию о конструкции в 'malloc' ... – SODIMM

+1

Этот вопрос может претендовать на тэг [language-lawyer]. –

ответ

0

Использование memcpy для таких целей будет определять поведение только в том случае, если фактический объект назначения не имеет статической или автоматической продолжительности.

Учитывая код:

struct foo { double const x; }; 
void outsideFunction(struct foo *p); 

double test(void) 
{ 
    struct foo s1 = {0.12345678}; 
    outsideFunction(&s1); 
    return 0.12345678; 
} 

компилятор будет иметь право оптимизировать функцию:

double test(void) 
{ 
    static struct foo const s1 = {0.12345678}; 
    outsideFunction(&s1); 
    return s1.x; 
} 

на многих процессорах, единственный способ загрузки двойной с произвольной константой является загрузите его значение из объекта, содержащего эту константу, и в этом случае компилятор будет удобно знать объект (s1.x), который должен содержать константу 0.12345678. Чистым эффектом было бы то, что код, который использовал memcpy для записи в s1.x, может испортить другие применения числовой константы 0.12345678. Как говорится, «переменные не будут, константы - нет». Неприятный материал.

Проблема не будет существовать для объектов с выделенной продолжительностью, потому что memcpy требует, чтобы компилятор «забыл» все о том, что ранее было , хранящееся в целевом хранилище, включая любой «эффективный тип». Заявленные типы статических и автоматических объектов существуют независимо от того, что в них хранится, и не могут быть стерты с помощью «memcpy» или каких-либо других средств, но объекты с продолжительностью продолжительности имеют только «эффективный тип», который будет удален.

+0

Это допустимый пример, но разве это не частный случай общей проблемы? Если вы исключаете структуры, которые состоят только из константных членов, то можно ли их копировать? – jxh

+0

@jxh: Я начал с более сложного примера, который потерпит неудачу в этом случае. Предположим, что у 'struct foo' были непостоянные члены, но функция взяла аргумент' v', инициализировал 's1.x' на' v + 0.12345678', а затем вернул 'v + 0.12345678'. Компилятор будет иметь право заметить, что значение в 's1.x' точно соответствует тому, что ему нужно вернуть, и, таким образом, загрузить это значение. Я мог видеть полезность иметь более сильную форму 'const', которая обещала бы, что если код прочитает значение объекта, любые последующие чтения этого объекта *, используя указатель, который был получен ... – supercat

+0

... из этого адреса объекта без конверсии любого типа * будут давать одно и то же значение, но это потребует признания того, что преобразования типов должны влиять на предположения компилятора относительно цели указателя. Я думаю, что очевидно, что они должны, но дизайн компиляторов, таких как gcc, затруднит это. – supercat