2017-02-19 20 views
4

Выполняет ли вызов memcpy на двух разных структурах, сохраняя исходные данные, если размер буфера достаточен? И определено ли это для получения значений другого типа данных с данными предыдущего типа данных, если их соответствующие типы данных перекрываются?Сохраняет ли memcpy данные между различными типами?

Это должно быть одинакова для обоих языков с/CPP, но я обеспечиваю пример в CPP -

#include <iostream> 
#include <cstring> 

using namespace std; 

struct A{ 
    int a; 
    char b[10]; 
}; 

struct B{ 
    int ba; 
    int bb; 
}; 

int main(){ 
    B tmp; 
    tmp.ba = 50; 
    tmp.bb = 24; 
    cout << tmp.ba << tmp.bb << "\n"; 

    // everything is fine yet 

    A obj; 
    memcpy(&obj, &tmp, sizeof(tmp)); 

    // 1. is this valid? 
    cout << obj.a << "\n"; 

    B newB; 
    memcpy(&newB, &obj, sizeof(newB)); 

    // 2. Are these valid? 
    cout << newB.ba << newB.bb << "\n"; 
} 

В приведенном выше примере я комментировал 1-й и 2-й комментарий, они действительны и данные сохранены если имеется достаточная буферная область? Можем ли мы сделать это переносимо?

Структура и другие связанные с ней функции находятся в библиотеке C, но мы будем использовать и скомпилировать ее с помощью C++.

+4

'memcpy' не знает и не заботится о типе данных. Он копирует количество указанных вами байтов, достаточно ли буфер назначения. Когда диапазоны перекрываются, поведение равно * undefined * и 'memmove' следует использовать. –

+1

'memcpy()' не гарантирует ничего в отношении базовых типов данных. –

+3

C или C++? Это два разных языка с совершенно другой объектной моделью. –

ответ

3

В стандарте C++ не указывается поведение memcpy, кроме отсрочки на стандарт C. (Возможно, чтобы избежать таких проблем!). В стандарте C он определяется как эквивалентный последовательности копий типа символа .

Таким образом, кажется разумным рассматривать memcpy(&obj, &tmp, sizeof(tmp)); как:

unsigned char *dst = (char *)&obj; 
unsigned char *src = (char *)&tmp; 
for (size_t i = 0; i != sizeof tmp; ++i) 
    dst[i] = src[i]; 

, а затем использовать стандарт C++, чтобы покрыть этот код.

Вопросы сейчас:

  1. ли &tmp, &obj фактически дать адрес начала объекта?
  2. Как насчет заполнения байтов в obj?
  3. Как насчет неинициализированных байтов заполнения в tmp?
  4. Что происходит со значениями под-объектов obj?

Выпуск 1: Да, это покрыто [class.mem]/19, так как нет базового класса субобъекты (и не перегружать operator&).

Вопрос 2: Я не могу найти текст, специально охватывающий это; но пример в стандарте копирования объекта класса в буфер символов и обратно в объект не будет работать, если не было разрешено писать байты заполнения.

выпуск 3: В [dcl.init]/12 есть текст, который явно разрешает использование вышеуказанного кода для неинициализированных данных; и пункт назначения будет содержать неопределенные значения. Поэтому, если неинициализированные байты заполнения в источнике отображаются только в неинициализированные байты заполнения адресата, это нормально. Но если они отображаются в под-объекты в месте назначения, то эти объекты будут иметь неопределенное значение.

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

Итак, в целом, я думаю, что ваш конкретный пример в порядке, если принять sizeof(A) >= sizeof(B).


В C, тетср также сохраняет эффективного типа объекта. У C++ есть другая объектная модель, и ее эквивалента нет. Поэтому, если вы использовали аналогичный код с компилятором C, вам также нужно будет соблюдать строгое правило псевдонимов между типами обоих объектов.

+1

о третьем пункте, это также должно поддерживать ваш аргумент - http://en.cppreference.com/w/cpp/language/data_members#Standard_layout, правильно? –

+0

@AbhinavGauniyal да, я изменю ответ –

+0

@ M.M, если я 'memset (.., 0, ..)' все структуры перед вызовом 'memcpy()' это должно решить проблему неинициализированных битов? – buggy3