2012-02-08 2 views
1

Скажем, у нас есть следующий код:C указатель/массив значение путаница

typedef union { 
    float e[4]; 
    __v4sf v; 
    float *s; 
} __vec4f; 

float test[12]; 


int main(){ 
__vec4f one; 

printf("adrs: &one.s = 0x%x, &one.e = 0x%x\n", &one.s, &one.e); 
printf("vals: one.s = 0x%x, one.e = 0x%x\n",one.s,one.e); 
one.s = test; 
printf("adrs: &one.s = 0x%x, &one.e = 0x%x\n", &one.s, &one.e); 
printf("vals: one.s = 0x%x, one.e = 0x%x\n",one.s,one.e); 

return 0; 
} 

При работе результаты, как следует:

adrs: &one.s = 0xbffff270, &one.e = 0xbffff270 
vals: one.s = 0x927ff590, one.e = 0xbffff270 
adrs: &one.s = 0xbffff270, &one.e = 0xbffff270 
vals: one.s = 0x52a0, one.e = 0xbffff270 

Один видит, что адрес one.s и one.e равны - как и ожидалось, но значений нет. Вот что меня смущает.

+0

Под память они одинаковые, но их интерпретация совсем другая – sidyll

ответ

1

one.e адрес одного.e массива. one.s - значение единицы. Если вам нужно значение e, вам нужно получить доступ к one.e [0] ... one.e [3].

0

«ценность» е является его адрес

Имя массива является только маркером для его адрес так arrayname и &arrayname одно и то же

+1

Это не совсем точная информация. –

0

Массив в любом контексте, кроме операнд оператора & или оператор sizeof оценивает адрес его первого элемента.

Кроме того, ваш код полон неопределенного поведения, потому что вы используете %x для печати указателей. %x действителен только в том случае, если (продвинутый) тип переданного выражения равен unsigned int.

1

«Значение» массива - это адрес первого элемента. Вы можете видеть это в ваших результатах. Если вы напечатали:

printf("vals: one.s = 0x%x, one.e[0] = 0x%x\n",one.s,one.e[0]); 

тогда вы должны получить те же ответы.

0

Компилятор рассматривает статически распределенные массивы по-разному, чем float ptr. Вы можете увидеть это в gcc путем компиляции с флагом -S. Вот код для первого и второго PRINTF заявления:

printf("adrs: &one.s = 0x%x, &one.e = 0x%x\n", &one.s, &one.e); 
    movl $.LC0, %eax 
    leaq -16(%rbp), %rdx 
    leaq -16(%rbp), %rcx 
    movq %rcx, %rsi 
    movq %rax, %rdi 
    movl $0, %eax 
    call printf 

printf("vals: one.s = 0x%x, one.e = 0x%x\n",one.s,one.e); 
    movq -16(%rbp), %rcx 
    movl $.LC1, %eax 
    leaq -16(%rbp), %rdx 
    movq %rcx, %rsi 
    movq %rax, %rdi 
    movl $0, %eax 
    call printf 

Вы можете видеть, что есть два «нагрузка эффективного адрес» инструкция для первого вызова (& one.s и & one.e), но только одна такая команда для второго вызова printf. Команда «leaq -16 (% rbp),% rdx» перемещает адрес% rbp-16 (на 2 байта меньше, чем хранилище адресов в регистре% rbp) в регистр% rdx, где он затем используется printf чтобы заполнить вывод для одного. В первой версии эта команда повторяется для загрузки того же адреса в% rcx.

Во второй версии регистр% rcx заполняется командой «movq -16 (% rbp),% rcx». В отличие от «leaq», «movq» - это инструкция для выполнения поиска в памяти для значения по указанному адресу (% rbp-16).