2013-10-24 2 views
1

Мне нужно объяснение. Я искал ответ, но не нашел его.Указатель void на функцию

Проблема заключается в следующем: Я работаю над упражнениями из книги: «Программирование для инженеров» А.Р. Брэдли Глава 7 Вот часть кода:

struct _fifo { 
    unsigned capacity; 
    unsigned head; 
    unsigned tail; 
    void * data[0]; 
}; 

fifo newFifo(int capacity) { 
    // The capacity of a circular buffer is one less than one 
    // would think: if the user wants a given capacity, the 
    // required array is one cell larger. 
    capacity++; 

    fifo q = (fifo) malloc(sizeof(struct _fifo) + capacity * (sizeof(void *))); 
    q->capacity = (unsigned) capacity; 
    q->head = 0; 
    q->tail = 0; 
    return q; 
} 

int putFifo(fifo q, void * e) { 

    if ((q->head+1) % q->capacity == q->tail) // full? 
     return -1; 
    q->data[q->head] = e; 
    q->head = (q->head+1) % q->capacity; 
    return 0; 
} 

typedef void (*printFn) (void*); 

int printFifo(fifo q, printFn f) { 

    unsigned i; 
    for (i = q->tail; i != q->head; i = (i+1) % q->capacity) { 
     f(q->data[i]); 
    } 
    return 0; 
} 

static void printLong(void * e) { 
    // %ld tells printf to print a long integer 
    printf("%ld", (long) e); 
} 

int main() { 
    fifo longq; 
    longq = newFifo(3); 

    printFifo(longq, printLong); 
    return 0; 
} 

Мой вопрос заключается в следующем: функция printLong я передаю пустой указатель е так делает бросок (длинный) е делает этот адрес е? почему я получаю значение данных, а не адрес, напечатанный?

, например, если я делаю это я получаю адрес напечатанный не значение:

typedef void (*printFn) (void*); 

static void printLong (void * e) { 
    printf("%ld", (long) e); 
} 

int printL (void* l, printFn f) { 
    f(l); 
} 

int main() 
{ 
    long a = 5; 
    long* l = &a; 

    printf("%ld\n", *l); 
    printL(l, printLong); 

    return 0; 
} 

но если я бросил

*(long*) e 

я получу значение. Как первая часть кода печатает значение, а не адрес? Думаю, я ничего не вижу, поэтому я смущен. Пожалуйста, помогите :)

+1

Не печатайте значения указателя. Используйте '% p' для вашего спецификатора формата и просто отправьте указатель. Если вы хотите напечатать длинный указатель на указатель на длинный, используйте% ld и разыщите указатель после соответствующего приведения, но убедитесь, что он содержит длинный адрес или вы идете в UB. Есть ли какая-то конкретная причина, по которой вы не просто объявляете 'long *' для вашего типа параметра? – WhozCraig

+3

Представлен ли этот пример кода с префиксом «Не пишете такой код»? Можете ли вы включить код из «newFifo»? Я пытаюсь определить, является ли «void * data [0]» оверлейным взломом или если он был взломан. В любом случае, происходит хитроумная хитрость, которая заставляет меня думать, что книге может понадобиться добавление экзотермического окисления. – kfsone

+0

Я действительно, действительно надеюсь, что этот код не взят из книги ... «Программирование потенциальным инженером»? – Lundin

ответ

0

в функции printLong я передаю указатель пустоты e так делает литье (long) e делает этот адрес e? как получается, я получаю значение данных , а не адрес напечатан?

no. Он накладывает указатель на длинный int. Если вы хотите получить адрес e, используйте вместо этого & e. Но e уже является адресом функции ... я не вижу смысла в получении адреса аргумента, потому что он находится в стеке.

Поэтому в основном я думаю, вы могли бы иметь некоторое недоразумение по имени функции functions.A не нравится имя Var:

  • var_name имеет значение, и вы используете & имя_переменные, чтобы получить адрес самого
  • function_name имеет значение адреса функции
    реализация и & имя_функции вернет то же значение
    (тот же адрес).

ОБНОВЛЕНИЕ:

Слово F (q-> данные [I]); чтобы получить printLong (void * e) - поэтому не следует указывать e = на q-> данные [i]?

В C аргументы функции передаются по значению. Значение q-> data [i] передается printLong(), поэтому аргумент e будет иметь одно и то же значение (тот же адрес), что и q-> data [i]. поэтому e является копией q-> данных [i]

+0

Я думаю, что я это понимаю, но я не вижу, как функция printLong получает указатель void e (адрес?) И печатает значение в этом адресе с (длинным) e - без адреса разыменования –

+0

e имеет адрес, но сам имеет адрес. вы просто бросаете его значение (так что адрес, который он хранит), чтобы долго. – tristan

+0

Да, поэтому у меня должен быть напечатан адрес e, но код в первой части сообщения печатает значение, а не адрес –

0

С моей точки зрения единственный способ распечатать назначенные значения - это присвоить их в качестве адресов вручную в указателе.

Пример

void * ptr=100; 
printf("%ld", (long)ptr); 

напечатает 100 на экране, но при попытке разыменования это вызовет (скорее всего) ошибки сегментации.

Так что, учитывая риски этой процедуры и, ну, вздор за длинные целые числа в пустоте * Я против даже рассматриваю это как полезный кусок кода.

+0

Я думаю, что ваш ответ такой же, как то, что вышло из обсуждения в другом. Только для вас было слишком кратким, чтобы я сразу понял. Спасибо. –

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