Reputation: 382
I need to write a function which writes an array of "n" elements to a binary output file. I would like to avoid having to write a separate function for each type of data I may wish to write (int, float, double, etc).
Is there any way I can specify the data type (perhaps number-of-bytes) as an argument to the function, and let the function determine how it handles it?
e.g.
f_writebinary(??? *data, int size, long n) {
for(i=0;i<n;i++) {
fwrite((data+i),size,1,stdout);
}
}
...or is this a totally absurd thing to expect of C?
Upvotes: 1
Views: 87
Reputation: 70971
Just replace ???
with char
. Or use void
and cast to char*
inside the function, so there is no need to cast to char*
when calling the function. And better use size_t
instead of int
and long
:
#include <stdio.h>
...
size_t f_writebinary(void * data, size_t size, size_t n)
{
size_t result = 0;
for (size_t i = 0; i < n; ++i)
{
size_t result_inner = fwrite(((char *) data) + (i * size), size, 1, stdout);
if (!result_inner)
{
/* handle error here */
}
else
{
++result;
}
}
return result;
}
Optimised version:
size_t f_writebinary(void * data, size_t size, size_t n)
{
size_t result = 0;
n *= size;
for (size_t i = 0; i < n; i += size)
{
size_t result_inner = fwrite(((char *) data) + i, size, 1, stdout);
if (!result_inner)
{
/* handle error here */
}
else
{
++result;
}
}
return result;
}
To cut it short: Just mimik the signature fwrite()
uses.
Upvotes: 1
Reputation: 399949
Yes, that's exactly what fwrite()
is. It uses a const void *
which means "pointer to any type of data", and treats it as a pointer to bytes.
So, your wrapper isn't really needed, you can just make a correctly-sized call to fwrite()
right away to write the array:
const int my_ints[3] = { 1, 2, 3 };
const double my_doubles[5] = { 5, 4, 3, 2, 1 };
fwrite(my_ints, sizeof *my_ints, sizeof my_ints / sizeof *my_ints, stdout);
fwrite(my_doubles, sizeof *my_doubles, sizeof my_doubles / sizeof *my_doubles, stdout);
Note that writing binary data to stdout
can be somewhat rude, and also that I/O calls should be checked for errors.
If you drop the "x elements of y bytes" model that fwrite()
's API uses, and just treat them as single chunks of bytes, you can simplify the calls:
fwrite(my_ints, sizeof my_ints, 1, stdout);
fwrite(my_doubles, sizeof my_doubles, 1, stdout);
Note that there's no point in looping, the numbers in each array will be adjacent in memory so fwrite()
can write them all at once. It's generally best to keep the number of I/O calls done down as much as possible, so if you can do a single write of n * m
bytes instead of n
writes of m
bytes each, that's almost often better. Remember that that many of the underlying devices that you write to are block-oriented, and will benefit a lot from getting whole blocks of data since that's what they have to write, anyway.
Upvotes: 2