1
votes

I need an explanaton. I searched for an answer but couldn't find one.

The problem is as follows: I'm working on exercises from the book: "Programming for Engineers" A.R. Bradley Chapter 7 Here's part of the code:

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;
}

My question is this: in function printLong i'm passing void pointer e so does the cast (long) e makes that adress of e? how come i'm getting a value of data and not the address printed?

for example if i do this i'm getting the address printed not the value:

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;
}

but if i cast

*(long*) e

i'll get the value. How come first code part prints the value not the address? I guess i don't see something so that's why i'm confused. Please help :)

2
Don't print pointer values like that. Use %p for your format specifier and just send the pointer. If you want to print the long pointed to by a pointer-to-long, then use %ld and dereference the pointer after an appropriate cast, but make sure it holds an address-of-long or you're walking into UB. Is there some specific reason you're not just declaring long* for your parameter type? - WhozCraig
Does this code example come with a prefix, "Don't write code like this"? Can you include the code from "newFifo"? I'm trying to determine if the "void* data[0]" is an overlay hack or if it is cast-avoidance hack. Either way, there's hack-trickery going on that makes me think the book may need an addendum of exothermic oxidization. - kfsone
I really, really hope this code is not taken from a book... "Programming by a would-be engineer"? - Lundin
Are you forced to use this book, or is this your personal choice? If the latter - flush that one in the toilet and pick some reccomended by people who know C textbook. I doubt it will be one of them. - zubergu
This book was recommended to me. I greatly enjoyed reading it. I'll add code for newFifo in main post as requested. - bob murley

2 Answers

0
votes

in function printLong i'm passing void pointer e so does the cast (long) e makes that adress of e? how come i'm getting a value of data and not the address printed?

no. It casts the pointer to a long int. If you want to get the address of e, use &e instead. But e is already the address of a function... i see no point in getting the address of a argument because it is on the stack.

So basically I guess you might have some misunderstanding on functions.A function name is not like a var name:

  • var_name has a value and you use &var_name to get the address
  • function_name itself has the value of the address the function
    implementation and &function_name would return the same
    value(the same address).

UPDATE:

I call f(q->data[i]); to get to printLong (void* e) - so shouldn't e be pointing to q->data[i] ?

In C, function arguments are passed by value. The value of q->data[i] is passed to printLong() so the argument e would have the same value(the same address) as q->data[i]. so e is a copy of q->data[i]

0
votes

From my point of view the only way it prints assigned values is by assigning them as addresses manually in your pointer.

Example

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

will print 100 on the screen, but trying to dereference it will cause (most likely) segmentation fault.

So considering the risks of this procedure and, well, nonsense of holding long integers in void* I'm against even considering this as useful piece of code.