Segfault дает головную боль - PullRequest
0 голосов
/ 22 марта 2011

В чем проблема со следующим кодом сейчас?

int main(){
union { 
        char arr[10];  
        int var;  
      } u;  
int *ptr_var= (int*) &(u.arr[1]);  
*ptr_var = 42; 
}

Ответы [ 4 ]

4 голосов
/ 22 марта 2011

Примечание: правильный ответ уже дан, это просто еще один способ объяснить фон.

При доступе к объектам в памяти большинство машин требуют, чтобы объекты были выровнены.Это означает, что четырехбайтовый (32-битный) объект должен быть размещен по адресу, который делится на четыре.Это происходит из-за того, что процессор связан с памятью с помощью шины данных, в нашем примере шина 32 бита.Если ЦП будет поддерживать невыровненные обращения, он должен будет запросить два доступа к памяти и сложить их вместе.Вместо этого большинство архитектур считают эту операцию недопустимой.

В вашем случае вы начинаете с объединения, которое хранится по четному четырехбайтовому адресу.Затем вы продвигаетесь на один байт вперед и пытаетесь получить доступ к int по адресу, который определенно не должен быть даже кратным размеру.

3 голосов
/ 22 марта 2011

Вы уверены, что это дает segfault? Название вводит в заблуждение !!

AFAIK на более старой архитектуре, это приведет к ошибке шины. Но, как этот пост объясняет, что вы не видите ошибку автобуса в эти дни.

Это может вызвать ошибку шины, поскольку объединение массив / int гарантирует, что массив символов arr также находится по разумно выровненному адресу для целого числа, которое &arr[1] определенно не выровнено должным образом для целого числа. И затем вы пытаетесь сохранить sizeof(int) байтов в адресе, который выровнен только для однобайтового доступа. Arghh !!!


1 голос
/ 22 марта 2011

Это легко и просто компилируется. Нет ошибки сегментации. Каков именно вывод вашего компилятора?

Здесь вы можете увидеть:

#include <stdio.h>

int main()
{
    int *ptr_var;
    union
    { 
        char arr[10];  
        int var;  
    } u;  

    u.arr[0]='A';
    u.arr[9]='\0';
    ptr_var = (int*) &u.arr[1];

    *ptr_var = 0x2a;

    printf("%s\n", u.arr);
    printf("%d(d)=%x(x)\n",u.var, u.var);
}

И ответ:

cpp/test/temp$ gcc union.c -o union
cpp/test/temp$ ./union 
A*
10817(d)=2a41(x)
cpp/test/temp$ gcc --version
gcc (Ubuntu 4.4.3-4ubuntu5) 4.4.3
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Это прекрасный способ перемещать биты. Возможно, ваш segfault находится в другой области программы. Смотрите этот тест:

*ptr_var = 0x10;
printf("%d(d)=%x(x)\n",u.var, u.var);

ptr_var = (int*) &u.arr[1];
*ptr_var = 0x10;
printf("%d(d)=%x(x)\n",u.var, u.var);

ptr_var = (int*) &u.arr[2];
*ptr_var = 0x10;
printf("%d(d)=%x(x)\n",u.var, u.var);

И вы получите:

16(d)=10(x)
4112(d)=1010(x)
1052688(d)=101010(x)

Береги себя, Беко.

0 голосов
/ 22 марта 2011

Это зависит от архитектуры. Я предполагаю, что стандарт может снова сказать, что поведение "неопределено". Я получаю разные результаты при запуске его на разных платформах:

1> Linux на X86: работает без проблем 2> Solaris на sparc: «Ошибка шины (ядро выгружено)».

...