0

if I input a binary file to array buf, why do I have to input it by (void*) ?? and why do I have to write it by (void*)?? please observe this code and please explain this code to me. (I just copy this code from my book)

int main(void) {
FILE * src = fopen("a.png", "rb");
FILE * des = fopen("b.png", "wb");

char buf[20];
int readCnt;

if (src == NULL || des == NULL) {
    puts("File open failed");
    return -1;
}

while (1) {
    readCnt = fread((void*)buf, 1, sizeof(buf), src);

    if (readCnt < sizeof(buf)) {
        if (feof(src) != 0) {
            fwrite((void*)buf, 1, readCnt, des);
            puts("File copy complete");
            break;
        }
        else
            puts("File copy Failed");

        break;
    }
    fwrite((void*)buf, 1, sizeof(buf), des);
}
fclose(src);
fclose(des);
return 0;

}

Jay
  • 1

4 Answers4

2

Because fread() & fwrite() are generic function for reading and writing binary data into file irrespective of their data type.

man page of fwrite() says,

size_t fwrite(const void *ptr, size_t size, size_t nmemb,
                     FILE *stream);

what is first arguement, its const void *ptr means its expecting address. it can be any variable address int or char or any other data type .

Achal
  • 11,821
  • 2
  • 15
  • 37
0

The cast to void* is because this is what the functions expect. See here and here.

Your code will compile without this cast, because cast to void* is not necessary (see quote below), but I guess the author wanted to be exact as possible.

6.3.2.3 Pointers

1 A pointer to void may be converted to or from a pointer to any incomplete or object type. A pointer to any incomplete or object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.

Another thing - (void*) is a good way to suppress compiler warnings. It may not be a good thing to begin with (warning are there for a reason), but if need be, this is a simple way to ignore wrong pointer type in function arguments.

CIsForCookies
  • 12,097
  • 11
  • 59
  • 124
  • IMHO it's bad style to have redundant pointer casts. Converting to/from `void *` is implicit for good reasons... –  Nov 15 '17 at 15:16
  • @FelixPalmen I Don't know. I see it a lot. A function expects `int*` but instead is provided a `unsigned int*`. The fix I see many times for this is `(void*)`. About bad style - totally agree. I don't write such code – CIsForCookies Nov 15 '17 at 15:19
  • The only "good" reason for a pointer to pointer cast is bad design. – Jens Gustedt Nov 15 '17 at 15:30
  • Indeed. But sadly not all of us write code top to bottom. Upon seeing such a problem that stems from bad design - this is a simple fix – CIsForCookies Nov 15 '17 at 15:34
  • @JensGustedt Or printing a pointer (more general, passing a generic pointer to a variadic function). Or aliasing with `char *` to examine the representation. But I agree you should avoid pointer casts because anywhere you need them is a place in the code that needs extra care not to violate strict aliasing etc. -- that's my primary argument against [casting the `malloc()` result](https://stackoverflow.com/q/605845/2371524). –  Nov 16 '17 at 08:26
0

This is so that you can pass any pointer type. So for example, if you want to write a structure like for example

struct point {
    int x;
    int y;
};

struct point my_point = {1, 2};
FILE *file = fopen("sample-file.bin", "w");
if (file != NULL) {
    // Normally check that this returns the number of
    // written items
    fwrite(&my_point, 1, sizeof(my_point), file);
    fclose(file);
}

would work, and when you open the file for reading you can fread(&my_point ...) too.

Note that casting to void * is not necessary in , nor is it needed to cast from void * to another pointer type, for instance

char *example = malloc(size + 1);

is perfectly valid and malloc() returns void *.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
0

This should probably be a comment but i don't have the reputation for that. In your code:

if (src == NULL || des == NULL) { puts("File open failed"); return -1; }

There is a chance that either src or des may have been opened correctly and therefore should have fclose(); called for it.

Something like:

if (src == NULL || des == NULL) 
{
      if(src)
      {
        fclose(src);
      }
      if(des)
      {
        fclose(des);
      }
      puts("File open failed");
      return -1;
  }

would be better.

mattc
  • 26
  • 4