简体   繁体   中英

Casting the void pointer and printing with format specifiers

Okay this is for a school project but my question has nothing to do with anything regarding a specific implementation , nor am I asking for any help regarding the project itself. I am only giving this warning because I want to give context for what I am doing, but this is rather a general question regarding the casting of void pointers, framed within the context of a project... This function I'm writing isn't even FOR the project, it's just something I wrote as a testing mechanism to see if my generation of a data structure is working... and it lead me to a problem involving printf(), format specifiers, and casting.... I basically have to implement a linked-list (called a 'queue' but is not really a queue at all), and I wrote a function to test it.

There is basically a struct called a "Chunk" with some variables ( first is the index within the larger array that is the first element of a given "Chunk", and arr is basically larger_array[c->first], but it's actually a void pointer as such: void *arr where c is a pointer to a Chunk) that indicate a position in a larger array. So basically if you have an array like a = {5,7,3,4,6,9,1,2}, and you were given a chunk size of two, you have 4 chunks each of whom have an "arr" void pointer variable which point respectively to 5, then 3, then 6, then 1.

Anyways, I wrote a "print_queue" function (actually a linked-list of Chunks) and yay! It prints all the information as desired, and here is the core part that I will share:

 while (index < num_chunks) {
    first = c->first;
    printf("Chunk %d: first is %d and a[%d] is ", index, first, first);
    if (elem_size == LONG_SIZE) /* LONG_SIZE defined above as 8 */
      printf("%ld\n", c->arr);
    else if (elem_size == INT_SIZE) /* INT_SIZE defined above as 4 */
      printf("%d\n", c->arr);
    else if (elem_size == CHAR_SIZE) /* CHAR_SIZE defined above as 1 */
      printf("%c\n", c->arr);

    index++;

    if (c->next != NULL)
      c = c->next;
 }

I basically wanted to write a function that would be able to print my linked-list for any of the three types (longs, ints, and chars) for testing purposes while I implement the actual functionality of the project (multithreaded merge-sort). So the code above actually works! This is the output for this array input:

 char original[] = {'z', 'y', 'x', 'w', 'v', 'u', 't', 's'};

Output:

 Chunk 0: first is 0 and a[0] is z
 Chunk 1: first is 2 and a[2] is x
 Chunk 2: first is 4 and a[4] is v 
 Chunk 3: first is 6 and a[6] is t

So it works! Yay! However, I get these compiler warnings:

mergesort.c: In function 'print_chunk_queue':
mergesort.c:85:7: warning: format '%ld' expects argument of type 'long int', but     argument 2 has type 'void *' [-Wformat]
mergesort.c:87:7: warning: format '%d' expects argument of type 'int', but argument 2 has type 'void *' [-Wformat]
mergesort.c:89:7: warning: format '%c' expects argument of type 'int', but argument 2 has type 'void *' [-Wformat]

So what I did was cast all the c->arr 's to (type *) c->arr, but that gave me more warnings about "oh we want an int but you have us an int pointer" so what I did was then:

 * ((type *) c->arr)

Basically dereferencing my casted void pointer (which is NEVER null! It always is pointing to valid numbers, at least with the input I provided it!), and then that gives me a segmentation fault!. So I'm pretty frustrated because I went from working output with a ton of "warnings" to useless segmentation faults.

EDIT:

definition of the data structure, as requested:

typedef struct chunk {
  void *arr;
  struct chunk *next;
  int first;
} Chunk;

this is how I am setting the state of a single chunk and creating a linked-list of chunks:

  while (index < number_of_chunks) {
    if (index == 0) {
      if ((current = malloc(sizeof(Chunk))) == NULL)
        err(EX_OSERR, "memory allocation has failed\n");
      head = current;
    }
    current->first = (chunk_size * index);
    current->arr = ((char *) array)[current->first];
    current->size = chunk_size;
    if (index != (number_of_chunks - 1)) {
      if ((current->next = malloc(sizeof(Chunk))) == NULL)
        err(EX_OSERR, "memory allocation has failed\n");
      current = current->next;
   }
  else {
    tail = current;
  }
  index += 1;
}
current->arr = ((char *) array)[current->first];

There should be an & here. You want to assign the address of the byte to arr rather than its value .

current->arr = &((char *) array)[current->first];

If you do that then arr will contain an address like it should, which will allow the casts & dereferences to work.

printf("%ld\n", *(long *) c->arr);
printf("%d\n",  *(int  *) c->arr);
printf("%c\n",  *(char *) c->arr);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM