Указатель Upcast и Downcast - PullRequest
1 голос
/ 03 июля 2011

Указатель Downcast

    int* ptrInt;
    char * ptrChar;
    void* ptrVoid;
    unsigned char indx;
    int sample = 0x12345678;

    ptrInt = &sample;
    ptrVoid = (void *)(ptrInt);
    ptrChar = (char *)(ptrVoid);

    /*manipulating ptrChar */
    for (indx = 0; indx < 4; indx++)
    {
        printf ("\n Value: %x \t Address: %p", *(ptrChar + indx), ( ptrChar + indx)); 
    }

Выход:

 Value: 00000078         Address: 0022FF74
 Value: 00000056         Address: 0022FF75
 Value: 00000034         Address: 0022FF76
 Value: 00000012         Address: 0022FF77

Вопрос: Почему выборка была разделена на данные размером с символ? И когда выполняется арифметика указателя, как он смог получить оставшееся значение? Как это было возможно?


Указатель Upcast

unsigned int * ptrUint;
void * ptrVoid;
unsigned char sample = 0x08;

ptrVoid = (void *)&sample;
ptrUint = (unsigned int *) ptrVoid;

printf(" \n &sample: %p \t ptrUint: %p ", &sample, ptrUint );
printf(" \n sample: %p \t *ptrUint: %p ", sample, *ptrUint );  

Выход:

 &sample: 0022FF6F       ptrUint: 0022FF6F
 sample: 00000008        *ptrUint: 22FF6F08    <- Problem Point

Вопрос: Почему в * ptrUint есть значение мусора? Почему стоимость мусора похожа в ptrUint? Следует ли использовать malloc () или calloc (), чтобы избежать этого мусорного значения? Какое лекарство вы бы предложили убрать из мусора?

Ответы [ 3 ]

1 голос
/ 03 июля 2011

В первом примере вы используете указатель на символ, поэтому данные будут доступны для байта за раз.Память адресуется в байтах, поэтому, когда вы добавляете один к указателю, вы получаете доступ к следующему более высокому адресу памяти.Это то, что происходит с циклом for.Использование указателя байта указывает компилятору на доступ только к одному байту, а остальные биты будут отображаться как 0, когда вы печатаете с% p.

Во втором примере я думаю, что происходитбайт выделен для выборочного байта, затем следующие 4 байта были выделены для ptrUint.Поэтому, когда вы получаете значение, начинающееся с адреса памяти образца и преобразующего его в 4-байтовый указатель, вы просто видите значение в образце плюс первые 3 байта ptrUint.Если вы приведете это к указателю на символ и напечатаете, вы увидите только 8 в выводе.

0 голосов
/ 03 июля 2011

Другие ответы уже объяснили почему вы видите то, что видите.

Я добавлю, что ваш второй пример опирается на неопределенное поведение . Недопустимо разыменовывать int *, который указывает на данные, которые изначально не были int. i.e.:

char x = 5;
int *p = (int *)&x;
printf("%d\n", *p);  // undefined behaviour
0 голосов
/ 03 июля 2011

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

В вашем первом примере вы рассматриваете указатель на целое число, как если бы он был указателем на символ (ы). Увеличение указателя на int добавляет 4 к нему, увеличение указателя на char добавляет 1 к нему (при условии 32-битных целых и 8-битных символов). Разыменование их делает int и char соответственно. Отсюда фрагментация в байты.

Во втором примере вы обрабатываете неподписанную переменную char с именем sample, как если бы она была указателем на int, и разыменовываете ее. По сути, вы читаете мусор с адреса памяти 0x08. Я полагаю, вы забыли &. Вы также передаете 1-байтовый символ и 4-байтовое int второму printf вместо 4 + 4 байтов, которые портят printf, считывая на 3 байта больше из стека, чем вы ему дали. Что по совпадению является частью значения ptrUint, переданного первому вызову printf. Использование% c вместо% p должно исправить это.

...