2010-12-16 3 views
1

Может ли кто-нибудь объяснить мне, что происходит в следующих двух строках кода? Предполагая, что мы работаем над 32-битной машинеУказатель Арифметический вопрос

р - это указатель

(*(long *)((char **)(p) - 1)) 
(*(int *)((int)(p) - 4)) 

Единственное, что я понял, что *(long *) преобразует «что-то», чтобы указатель типа long и затем deref. чтобы получить значение.

Спасибо!

+3

я бы * надежда * это на 32-битной машине. Этот код является 64-битным небезопасным. – 2010-12-16 05:48:24

+0

Что такое `p`? [MoreCharactersToAppeaseJeffAtwood] – 2010-12-16 05:48:31

ответ

1
(*(long *)((char **)(p) - 1)) 

Начинайте с указателем р. Передайте его типу (char **). Вычтите один из него. Передайте результат типу (long *), а затем разыщите результат. Другими словами, сдвиньте указатель на один байт и получите значение длинного, сохраненного на этом адресе. Эта операция может быть разбита на некоторых платформах, особенно в зависимости от типа p.

(*(int *)((int)(p) - 4)) 

Начать с указателя. Передайте его в int. Вычитание 4. Передайте его (int *) и разыщите результат. Теперь вместо обычной арифметики указателя вы прямо играете со значением указателя в виде целого числа, сдвигая его на четыре и читая int, на который указывает результат. Эта операция также будет нарушена в некоторых системах.

Думаю, мне удалось разобрать это, не заблудившись в парнах. В любом случае, не делайте этого. Это патологично. Там может быть какая-то странная встроенная задача разработки, где вы думаете, что что-то вроде этого - хорошая идея. Если это так, никогда не признавайте, что сделали это. Обвините его кому-нибудь, если он будет обнаружен.

Например, во втором примере, с р как INT *, а в системе с 8-битных символов и 32-битных целых чисел, вы в основном выполнения * (P-1)

OTOH, на машина с 16-битным int, вы делаете * (p-2), а на машине с 64-битным int вы делаете * (p-0.5), что неразумно, и может сильно сбой, а просто жаловаться о непринятом доступе к памяти. (И он заслуживает краха.) Используйте указатели, которые на самом деле указывают на правильный тип, и у вас никогда не должно быть причин делать такие глупости.

1
(*(long *)((char **)(p) - 1)) 

    Looks like getting the length of some kind of length byte character array 
that was passed by reference. But that is just first glance.. 

    (p) = some object 

    (char **) casts some object to the address of the address of a character, which is a 32bit value sizeof(char**) 

    -1 gets the 32bits in memory prior to (char **)(p) 
    *(long*) does what you thought, takes that 32bits, casts it as a long *, and dereferences it. 
    So there is a record in memory like: 

    struct {long * n; char ** s; } 
    similiar to what happens in parameter passing. 

(* (INT *) ((INT) (р) - 4))

это один уродливее. Некоторые объекты p передаются в int, давайте просто надеемся, что sizeof (int) равно 32, так что это может быть адрес, вычесть из него 4 (адреса по-прежнему считаются байтами, 4 байта - 32 бита), которые в качестве указателя на int , и разыгрывать его.

Для дополнительного кредита сравнить его: * ((INT *) ((INT) (р)) - 1)

1

1: ((символ **) (р) - 1): литой р, чтобы указать на массив массивов символов и вычитать (так что теперь, как & р [-1])

(длинный *): нарисуйте его на указатель на long и последний займет этот адрес.

2: ((INT) (р) - 4): приведение р в целое и вычитаем 4

(интермедиат *): брось, чтобы указать на массив Int и захвати ИНТ с этого адреса

1

Первый раз задолго до p.
Для x32 SizeOf (Char *) == SizeOf (длинный), поэтому (длинный *) (символ * ) есть (длинный)
Так что это просто *((long*)p - 1 ) или ((long*)p)[-1]

Вторая строка делает то же самое, но он дает int вместо long. (long*)p - 1 тот же адрес, как (int)p - 4, потому что SizeOf (длинная) == 4.

1

Учитывая р является указателем на двухмерном массиве для .eg

int a[][5] = {10,20,30,40,50,11,21,31,41,51,12,22,32,42,52,13,23,33,43,53,14,24,34,44,54}; 
int (*p)[5] = a; 

Теперь для простоты мы предполагаем, адрес из а [0] [0] в 1000

Теперь позволяет оценить (*(long *)((char **)(p) + 1));

  1. даст вам адрес [0] [0] >>>> т.е. 1000
  2. (char **)(p) + 1 добавит SizeOf Int к вашему адресу >>>> т.е. 1004
  3. (* (длинный *)) получит значение по адресу 1004, который является 20 в нашем примере

(*(long *)((char **)(p) + 1)); будет оценивать до 20 в нашем случае

Смежные вопросы