Структура памяти макета В С - PullRequest
0 голосов
/ 16 января 2012
struct fraction {
    int num;
    int denum;
} pi;

pi.num=22;
pi.denum=7;

((fraction*)&(pi.denum))->num=12;

cout << endl;
cout << pi.denum <<endl;
cout << pi.num   <<endl;

Я могу понять диаграмму памяти до этого момента. Я запутался в следующем коде

((fraction*)&pi.denum)->denum=33;

Есть ли законный способ распечатать эти 33?ЛЮБАЯ команда, чтобы получить сохраненное значение, которого нет в объекте?

Ответы [ 6 ]

1 голос
/ 16 января 2012

Может быть, поможет простое изображение:

A+0  pi.num
A+4  pi.denum

A - это базовый адрес, где pi хранится в памяти.num хранится по адресу A+0, а denum хранится по адресу A+4 (если int составляет 32 бита, т.е. 4 байта).

Часть ((fraction*)&(pi.denum)) операторараскладка будет выглядеть примерно так:

A+0  pi.num
A+4  pi.denum   ((fraction*)&(pi.denum))->num
A+8             ((fraction*)&(pi.denum))->denum

Как видите, в памяти есть совпадение.Это означает, что оператор ((fraction*)&(pi.denum))->num=12; фактически установит pi.num в 12.

Также, как вы можете видеть, если вы пытаетесь установить ((fraction*)&(pi.denum))->denum в значение, вы теперь пишете вне выделенной памятив структуру pi и может перезаписывать другие переменные или другие вещи.

1 голос
/ 16 января 2012

A struct fraction будет размещено в памяти как два последовательных ints.Ваш код просматривает выражение &pi.denum, являющееся адресом второго целого числа:

 -----------------------   
|  int num  | int denum |
 -----------------------
 ^           ^
 |           |
 &pi         &(pi.denum)

Но вы преобразуете &pi.denum в fraction * и пытаетесь получить доступ к ((fraction*)&(pi.denum))->num.Поскольку num является первым членом struct fraction, стандарт C гарантирует, что его адрес совпадает с самой структурой.Так что

&(((fraction*)&(pi.denum))->num) == (fraction*)&(pi.denum) == &pi.denum.

Это является допустимым местом в памяти - но только по счастливой случайности.Если вы попытаетесь получить доступ к ((fraction*)&(pi.denum))->denom, вы получите неопределенное поведение - возможно, повреждение памяти или ошибка сегментации.

Итог, ((fraction*)&(pi.denum))->num = 12 - бессмысленный код.Он никогда не сможет сделать ничего полезного.

0 голосов
/ 16 января 2012

В коде, опубликованном в вашем вопросе, вы указали компилятору действовать так, как будто адрес pi.denum на самом деле является адресом fraction struct.

Это не так, и поэтому высамостоятельно в получении правильной адресации памяти.C (или C ++) разместит вашу структуру в памяти в указанном вами порядке, с учетом только заполнения для выравнивания.

Итак, на машине с 32-разрядными целочисленными значениями и типичным 32-разрядным выравниванием для 32-в битах, ваша строка ((fraction*)&(pi.denum))->num=12; установит pi.denum в 12, а не pi.num.->num - это смещение от указателя (смещение равно нулю), а ваш указатель равен pi.denum, поэтому устанавливается pi.denum.

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

Следующий код ((fraction*)&pi.denum)->denum=33; будет записывать в память вне выделения pi.Сбой или просто перезапись другой переменной зависит от того, что еще вы распределили в стеке, и, возможно, от настроек компилятора и компилятора.

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

int myTest = ((fraction*)&pi.denum)->denum;
0 голосов
/ 16 января 2012

При условии, что этот код в основном неправильный , возможно, вы ищете это:

#include <iostream>

int main () {

    struct fraction {
        int num;
        int denum;
    } pi;

    pi.num=22;
    pi.denum=7;

    ((fraction*)&(pi.denum))->num=12;

    std::cout << std::endl;
    std::cout << pi.denum <<std::endl;
    std::cout << pi.num   <<std::endl;

    ((fraction*)&pi.denum)->denum=33;

    int * items;
    items = (int *)&pi;

    for (int i = 0; i < 3; i ++) {
        std::cout << i << ": " << items[i] << std::endl;
    }

}
0 голосов
/ 16 января 2012

Эта строка, вероятно, установит pi.denum в 12, но это неопределенное поведение.Член "num" находится (в большинстве случаев) в начале структуры, поэтому something.num похоже на (int)something (конечно, это something должно быть дробным), но вы не должны предполагать, что это будет работатьна каждой машине.

0 голосов
/ 16 января 2012

Во-первых, если вы хотите распечатать 33, вам нужно использовать следующую инструкцию:

((fraction*)&pi.denum)->num=33;

Теперь разберитесь в механизме доступа к памяти C, в котором доля struct имеет два элемента int.Базовый адрес структуры указывает на адрес первого элемента.

& pi.denum дает адрес второго элемента, теперь вы приводите его к указателю структуры, так что он обрабатывает адрес denum как логический, а физически адрес denim.

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

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