Что не так с этим C броском - PullRequest
3 голосов
/ 18 января 2010

Я наткнулся на это вчера на канале IRC и не понял, почему это было плохое поведение:

#include <stdio.h>

int main(void)
{
     char x[sizeof(int)] = { '\0' }; int *y = (int *) x;
     printf("%d\n", *y);
}

Есть ли потеря данных или что-то еще?Может кто-нибудь дать мне какие-нибудь документы, чтобы объяснить, что это не так?

Ответы [ 4 ]

10 голосов
/ 18 января 2010

Массив x может быть неправильно выровнен в памяти для int. На x86 вы не заметите, но на других архитектурах, таких как SPARC, разыменование y вызовет ошибку шины (SIGBUS) и приведет к сбою вашей программы.

Эта проблема может возникнуть для любого адреса:

int main(void)
{
    short a = 1;
    char b = 2;

    /* y not aligned */
    int* y = (int *)(&b);
    printf("%d\n", *y); /* SIGBUS */
}
7 голосов
/ 18 января 2010

С одной стороны, массив x не гарантируется для правильного выравнивания для int.

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

То же самое не верно для памяти, выделенной компилятором для автоматических переменных.

0 голосов
/ 19 января 2010

Я думаю, что хотя проблема выравнивания верна, это еще не все.Даже если выравнивание не является проблемой, вы все равно берете 4 байта в стеке, только один из них инициализируется нулем, и рассматриваете их как целое число.Это означает, что напечатанное значение имеет 24 неинициализированных бита.И использование неинициализированных значений является базовым «неправильным».

(для простоты предполагается, что sizeof (int) == 4).

0 голосов
/ 18 января 2010

Почему бы не использовать вместо этого союз?

union xy {
    int y;
    char x[sizeof(int)];
};
union xy xyvar = { .x = { 0 } };
...
printf("%d\n", xyvar.y);

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

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