Как это работает? копирование чего-либо в массив байтов (символов) - PullRequest
2 голосов
/ 22 сентября 2010
struct MyRect
{
    int x, y, cx, cy;
    char name[100];
};

int main()
{
    MyRect mr;
    mr.x = 100;
    mr.y = 150;
    mr.cx = 600;
    mr.cy = 50;
    strcpy(mr.name, "Rectangle1");

    MyRect* ptr;

    {
        unsigned char bytes[256];

        memcpy(bytes, &mr, 256);

        ptr = (MyRect*)bytes;
    }

    printf("X = %d\nY = %d\nCX = %d\nCY = %d\nNAME = %s\n", 
        ptr->x, ptr->y, ptr->cx, ptr->cy, ptr->name);

    return 0;
}

Я просто проверял, как поместить структуру / класс в массив байтов, и был удивлен, когда он скомпилирован и работал, printf выводит все значения, которые я установил в переменной mr

просто немного запутался в том, на что именно указывает "ptr"? он выделил память для ptr где-нибудь?

Ответы [ 6 ]

9 голосов
/ 22 сентября 2010

работает по чистой случайности.

Во-первых, вы в основном делаете побайтовую копию структуры и помещаете ее в выделенный стеком буфер, используя memcpy. Тем не менее, вы не должны делать это на практике. В этот раз это сработало, потому что ваша структура - POD (plain-old-data или C-struct), но если ваша структура была объектом C ++ с конструкторами / конструкторами копирования или чем-то еще, возможно, вы получили неприятный сюрприз.

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

2 голосов
/ 22 сентября 2010

unsigned char bytes[256] выделяется в стеке, то есть каждый раз, когда вводится ваша функция (в данном случае main), 256 байтов резервируются в стеке для переменной bytes. И через приведение ptr теперь указывает на эту область в стеке и интерпретируется как тип MyRect. Поскольку вы сначала скопировали такую ​​структуру в область стека, все в порядке и допустимо. Но как только вы покидаете main, область, на которую указывает ptr, исчезает, поэтому вы не можете хранить указатель на эту область вне этой функции.

2 голосов
/ 22 сентября 2010

Что ж, ваша программа вызывает неопределенное поведение, так что вы, вероятно, не должны удивляться тому, что это работает.Или, если это не сработало или вызвало конец вселенной, в этом отношении.После того, как ваш блок, содержащий определение bytes, ptr выходит за пределы области и может указывать или не указывать на действительную память.В вашем случае это так.Но вы не можете полагаться на это поведение.

1 голос
/ 22 сентября 2010

ptr все еще указывает на адрес bytes.Или то, что когда-то называлось bytes.Даже если вы поместили bytes в свой собственный блок, и переменная семантически недоступна вне этого блока, память остается неизменной до выхода из функции.Это типичный метод реализации, но он не определен стандартом, поэтому не зависите от него.

0 голосов
/ 22 сентября 2010

Это работает, потому что, хотя массив 'bytes' находится вне области видимости, пространство стека, в котором он находится, не было добавлено к моменту вызова printf ().Это также работает, потому что, хотя 'mr' не имеет размера 256 байт, память, следующая за ним (в стеке), не заботится о том, что вы ее читаете.

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

Так что я согласен, ваша программа в основном работает случайно.Но это так, потому что C позволяет делать некоторые дикие вещи с указателями.

0 голосов
/ 22 сентября 2010
ptr = (MyRect*)bytes;

"байты" - это адрес массива в памяти.

ptr получает этот адрес в этом коде.

Приведение говорит компилятору игнорировать разницу в данныхТипы.

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

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