2016-10-27 11 views
-2
#include <stdio.h> 
#include <stdlib.h> 
void process_keys34 (int * key3, int * key4) { 

    *(((int *)&key3) + *key3) += *key4; 
} 
int main (int argc, char *argv[]) 
{ 
int key3, key4; 
if (key3 != 0 && key4 != 0) { 
     process_keys34(&key3, &key4);//first time 
    } 

if (true) { 
      process_keys34(&key3, &key4); 
      msg2 = extract_message2(start, stride);//jump to here 
      printf("%s\n", msg2); 
     } 
    } 

Я тестирую этот код на macOS 10.12, используя Xcode7.Почему p & key3 + 2 и p (int *) & key3 + 2 будут печатать разные результаты в LLVM?

Вопрос можно описать просто как

Почему &key3 == (int*)&key3

но &key3 + 2 != (int*)&key3 + 2

и &key3 + 2 == (int*)&key3 + 4

при использовании XCode7

Я установил KEY3 и КЛЮЧ4 из ARGV, Я хочу прыгать с process_keys34(&key3, &key4);//first time до

msg2 = extract_message2(start, stride);//jump to here.

Поэтому я должен изменить значение обратного адреса func process_key34. Поскольку существует ключ var4 между & key3 и адресом возврата, поэтому я должен добавить 2 к & key3, что означает, что key3 должен быть 2. Но правда в том, что key3 должен быть 4, тогда результат правильный.

Затем выполните некоторые испытания в lldb. я обнаружил, что

(lldb) p *(&key3 + 2) 
(int *) $6 = 0x0000000100000ec3 //that's right. 

но

(lldb) p *((int*)&key3+2) 
(int) $8 = 1606416192// I dont know what does that mean. 

я проверить, что

(lldb) p &key3 
(int **) $5 = 0x00007fff5fbff6d8 
(lldb) p (int*)&key3 
(int *) $7 = 0x00007fff5fbff6d8 

Я нашел эти две такие же.

но &key3 + 2 ,(int*)&key3 + 2 отличаются друг от друга.

(lldb) p &key3 + 2 
(int **) $9 = 0x00007fff5fbff6e8 
(lldb) p (int*)&key3 + 2 
(int *) $10 = 0x00007fff5fbff6e0 

и &key3 + 2 ,(int*)&key3 + 4 такие же

(lldb) p &key3 + 2 
(int **) $9 = 0x00007fff5fbff6e8 
(lldb) p (int*)&key3 + 4 
(int *) $14 = 0x00007fff5fbff6e8 

Я обнаружил, что & ключ3 является INT ** и (интермедиат *) & ключ3 является INT *, который является единственным различием между этими двумя командами. Но я все еще не понимаю, почему это произошло.

Поскольку в результате сближения с C99 правая часть + изменится на один и тот же тип слева, это означает, что intger 2 будет чередоваться с int * или int **. Но я думаю, что они не имеют разницы, потому что sizeof (int *) == sizeof (int **).

Я не знаю, почему это произошло. Может ли кто-нибудь мне помочь?

+1

Код вызывает неопределенное поведение, используя неинициализированные переменные. Я думаю, из ваших комментариев, что «реальный код» отличается и инициализирует переменные. Но даже в этом случае код продолжает вызывать неопределенное поведение из-за доступа вне границ. В C или C++ не разрешено выполнять арифметику указателя по адресу переменных и тем самым получать доступ к другой переменной. Чтобы сделать это, вы должны использовать массив. –

+1

Представьте, что вы рассматриваете вещи как массивы. int * будет похож на массив ints, int ** больше похож на массив int *. По мере того, как работает указатель math, int * + 2 будет увеличиваться на 2 * sizeof (int). int ** + 2 будет увеличиваться на 2 * sizeof (int *). Первый, скорее всего, «2 * 4», а последний, скорее всего, «2 * 8» на 64-битной платформе. – Charlie

+0

Связанный: http://stackoverflow.com/questions/394767/pointer-arithmetic – alk

ответ

0

Причина &key3 и (int *)&key3 (обратите внимание, что я считаю, что key3 - это int *) имеет такой же тип.

Это имя pointer arithmetic.

На некоторой системе sizeof(int) != sizeof(int *).Так, (int *) + 2 это не тот же эффект, что (int **) + 2 потому что

(int *) + 2 ==> * + (2 * sizeof(int)) 

(int **) + 2 ==> * + (2 * sizeof(int *)). 
3

вы видите результаты не имеют смысла (если не смотреть на сгенерированной сборки, но это не входит в рамки вопроса).

Код имеет два случая неопределенного поведения.

Переменные ключ3 и Key4 используется неинициализированным:

int key3, key4; 
if (key3 != 0 && key4 != 0) { 

В следующей строке переосмысливает сохраненное значение объекта Key3, который имеет типа Int * с несовместимым типом INT:

*(((int *)&key3) + *key3) += *key4; 

Другими словами, тип int записывается в key3, который имеет тип int *.