I'm writing a little library and struggling with the naming conventions. There is a structure called gk_Stream defined as follows:
typedef struct gk_Stream {
gk_Stream_writeProc write;
gk_Stream_readProc read;
void* data; // Pointer to data needed by read and write procedures.
} gk_Stream;
Now, I want to supply 2 built-in uses for this structure.
Reading/Writing from/to a FILE*
Reading/Writing from/to a buffer
I first called the functions like the following:
gk_Stream_initWithFile(gk_Stream* stream, FILE* fl);
gk_Stream_initWithBufferSize(gk_Stream* stream, size_t bufferSize);
gk_Stream_initWithStringAndBufferSize(gk_Stream* stream, char* string, size_t string_length, size_t buffer_size);
gk_Stream_deallocBuffer(gk_Stream* stream);
But another possibility would be to call them like this:
gk_Stream_file_init(/* */);
gk_Stream_buffered_initWithSize(/* */);
gk_Stream_buffered_initWithStringAndSize(/* */);
gk_Stream_buffered_dealloc(/* */);
What names do you think make most sense or look/sound best? What are the names you would want to work with when using the library?
How about:
gk_Stream_file_init(gk_Stream* stream, FILE* fl);
gk_Stream_file_deinit(gk_Stream* stream); /* not sure if necessary */
gk_Stream_buffer_init(gk_Stream* stream, size_t bufferSize);
gk_Stream_buffer_initWithString(gk_Stream* stream, char* string, size_t string_length, size_t buffer_size);
gk_Stream_buffer_deinit(gk_Stream* stream);
When I hear or read "buffered", I think of that as the method used internally to improve performance when writing to/reading from things such as files or pipes. However, that's not what's going on here. Your code can either do I/O with a file or with a buffer, so it makes sense for the function names to differentiate between performing operations on a file vs a buffer, not file and buffered.
Edit: Oh, I forgot to explain one other thing; I also would prefer deinit to dealloc, as deinit is the natural companion to init. Deallocating is perhaps how you are deinitializing the stream, but all the user of your library needs to know is that they are deinitializing the stream.
I would do this:
gk_Stream_InitWithFile(gk_Stream* stream, FILE* fl);
gk_Stream_Deinit(gk_Stream* stream);
gk_Stream_InitWithBufferSize(gk_Stream* stream, size_t buffer_size);
gk_Stream_InitWithStringAndBufferSize(gk_Stream* stream, char* string, size_t string_length, size_t buffer_size);
underscores to separate "namespaces", CamelCase for function names. lower_case for variables.
There's no standard/recommended naming conventions in C.
Use whatever you feel is best for code readability, consistent with the naming conventions followed in rest of the code/project.
It somewhat depends upon the purpose of the string argument in the buffered case.
I'd probably go with something like:
gk_Stream_file_init(gk_Stream *stream, FILE *f);
gk_Stream_mem_init(gk_Stream *stream, size_t buff_sz, const char *initval, size_t initval_sz);
gk_Stream_mem_free(tk_Stream *stream);
And then allow a NULL initval.
Related
I have the following function and I am wondering if there is a way to pass string or char array instead of stdout into it so I can get the printed representation as a string.
void print_Type(Type t, FILE *f)
{
fprintf(f,"stuff ...");
}
print_Type(t, stdout);
I have already tried this:
int SIZE = 100;
char buffer[SIZE];
print_Type(t, buffer);
But this is what I am seeing:
�����
Something like this
FILE* f = fmemopen(buffer, sizeof(buffer), "w");
print_Type(t, f);
fclose(f);
The fmemopen(void *buf, size_t size, const char *mode) function opens a stream. The stream allows I/O to be performed on the string or memory buffer pointed to by buf.
Yes there is sprintf() notice the leading s rather than f.
int SIZE = 100;
char buffer[SIZE];
sprintf(buffer, "stuff %d", 10);
This function prints to a string s rather than a file f. It has exactly the same properties and parameters to fprintf() the only difference is the destination, which must be a char array (either statically allocated as an array or dynamical allocated (usually via malloc)).
Note: This function is dangerous as it does not check the length and can easily overrun the end of the buffer if you are not careful.
If you are using a later version of C (c99). A better function is snprintf this adds the extra buffer length checking.
The problem with fmemopen is that it cannot resize the buffer. fmemopen did exist in Glibc for quite some time, but it was standardized only in POSIX.1-2008. But that revision included another function that handles dynamic memory allocation: open_memstream(3):
char *buffer = NULL;
size_t size = 0;
FILE* f = open_memstream(&buffer, &size);
print_Type(t, f);
fclose(f);
buffer will now point to a null-terminated buffer, with size bytes before the extra null terminator! I.e. you didn't write null bytes, then strlen(buffer) == size.
Thus the only merit of fmemopen is that it can be used to write to a fixed location memory buffer or fixed length, whereas open_memstream should be used everywhere else where the location of the buffer does not matter.
For fmemopen there is yet another undesired feature - the writes may fail when the buffer is being flushed and not before. Since the target is in memory, there is no point in buffering the writes, so it is suggested that if you choose to use fmemopen, Linux manual page fmemopen(3) recommends disabling buffering with setbuf(f, NULL);
I have this fragment
fseek(sp,f_line*fm,SEEK_SET);
fgets(buffer,LEN,(FILE*)sp);
I don't understand this part
(FILE)sp
I try to fill a char array with data from a file.
Apparently, someone thinks they are storing a file pointer in a variable sp that is not of type FILE *, so it is reputed to be necessary to cast the type to FILE *. See the POSIX definition of fgets(), which is meant to be equivalent to the standard C definition of the function.
However, given that the prior line calls fseek() with an uncast sp, and fseek() also expects a FILE *, someone is confused — the person writing the cast is confused.
The cast should be removed from the call to fgets().
Or, possibly but implausibly, the cast should be added to the call to fseek().
One outré possibility is that the user defined void *sp and used that to store the FILE * returned by fopen() or equivalent. Such a decision would be extremely unorthodox, and pointlessly opens up the code to type confusion, but could actually allow the code shown below to compile and run — but the cast is still unnecessary.
/* Abominable code - do not use! */
#include <stdio.h>
int main(void)
{
void *sp = fopen("abuse47.c", "r"); // The abomination!
if (sp != 0)
{
char buffer[256];
fseek(sp, 120, SEEK_SET);
if (fgets(buffer, sizeof(buffer), sp) != 0)
printf("[%s]\n", buffer);
fclose(sp);
}
return 0;
}
i've got a Textfile of Unknown Size and have to send it via Sockets from my Server to the Client in Chunks of a certain (variable Size).
How can i use Fread for that Task? I read alot about Fread but im Struggeling with the kind of Pointer i should pass that function in my Case?
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
How can i use fread for that task?
Simply keep sending chunks (of fixed size) from the Server to the Client, until there is nothing else to be sent by the Serve.
What kind of pointer I should pass that function in my case?
Anything.
Check fread()'s example, where the buffer that is passed in fread() is of type char, and fread() simply allows for it, since the first argument of that function is:
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
So just pass the array you are using to store the data (the chunks) to the function.
To read file as chunks and send them to socket you'll have to decide a size of the chunk.
For example: 4096 is perfect size that's not too big or not too small!
Example
We choose 4096 bytes as the chunk size. It's btw customizable.
Send the chunk data to the Client when received from file.
#include <stdio.h>
int main(ssize_t argc, char** argv)
{
// We're going to use "rb" because in (WINDOWS) you need it!
FILE* fp = fopen(argv[1], "rb");
char byte_buffer[4096];
size_t bytes_read = 0;
while(( bytes_read = fread(&byte_buffer, 4096, 1, fp) )> 0)
send_data_chunk_to_client_somehow(/* your parameters here */);
}
The text file should be read in chunks and send them to the Client.
fread(3) ― Binary stream I/O
fread(3) is compatible with both text and binary streams, it's a part of ANSI C. The POSIX read(3) is a equivalent to the function and faster than it.
size_t fread(void* ptr, size_t size, size_t nmemb, FILE* fp);
If I have piece of code that writes out text like this: write(1, buf, bytes); why doesn't the same works for writing to a file fwrite(1, buf, bytes,f1);?
Where f1 is declared as FILE *f1; and f1=fopen("Test.txt", "wb");. The tutorials I'm looking at indicate that it should work. I'm C# coder and not a C coder and would like some help with this.
The signature of fwrite is:
fwrite(const void * ptr, size_t size, size_t count, FILE * stream );
While the signature of write is:
write(int fd, const void *buf, size_t count);
If you match your examples you'll see that parameter don't match.
count of write should be size*count of fwrite (which let you specify the size of every element you are writing). In addition write has a file descriptor hardcoded as 1 and which you replace with a FILE* obtained from fopen, how do you know that 1 is referring to that file?
C# has a neat feature of being able to write to a memory stream using the MemoryStream object.
I'm looking for similar functionality from C using a FILE* pointer.
I want to be able to sprintf() but with the added functionality of having C remember "where I was" in the buffer I'm writing to.
If you are using the GNU C Library, you can use fmemopen(). There may be other non-portable extensions for other environments, but there's no portable way using FILE*s.
You could also, however, wrap snprintf, if you don't insist on actually using FILE*s. For example, glib (note: not the same as the GNU C Library, and portable) has a g_string_append_printf that does what you want.
There's also an ugly hack which works with plain ISO-C: You can use fopen() to open a null file (/dev/null on *nix, NUL on Windows) and set the array as the file's buffer via
setvbuf(file, buffer, _IOFBF, buffer_size)
This should work fine as long as fflush() isn't called anywhere in the code. Also, the programmer has to explicitly take care of the string delimiter.
I don't really see a need to do this, though: As snprintf() returns the number of characters written, it's trivial to keep track of a buffer's position.
One can even write a function to automagically resize the buffer on overflow: bufprintf.c
The function's prototype is
int bufprintf(char **buffer, size_t *size, size_t *offset,
const char *format, ...);
An example program could look like this:
#include <stdio.h>
extern int bufprintf(char **buffer, size_t *size, size_t *offset,
const char *format, ...);
int main(void)
{
size_t size = 0; // must be set!
size_t offset;
char * buffer;
for(int i = 0; i < 100; ++i)
bufprintf(&buffer, &size, &offset, "we rock %i\n", i);
puts(buffer);
printf("size:\t%u\noffset:\t%u\n", (unsigned)size, (unsigned)offset);
}
sprintf returns the number of characters that were printed into the string. You can use that value to increment the pointer of your buffer.
buffer += sprintf(buffer, "%d", i);
Make sure that you keep around a copy of the original pointer, as that is what you will be using when passing the buffer somewhere else.
Why not use mmap? You can map a file to memory and use a FILE* pointer.
Update: It does not work. Sorry.
MemoryStream is not a feature of C#, the language. It's simply a class in the BCL. You could write it yourself in C#.
And so it is in C - you'd write some functions that work similarly in use to fopen, fprintf, fwrite, fclose, etc., but give them names like mopen, mwrite, etc. (presumably) and write them so they operate on a memory buffer.
How about just manually managing your pointers. I don't have a compiler in front me but hopefully the code below gets the idea across:
char huge_buffer[REALLY_BIG_SIZE];
char *write_pos = huge_buffer;
//...
void fprintf_to_mem(char **mem_ptr, const char *fmt, ...)
{
va_list args;
int num_written;
va_start(args, mem_ptr);
num_written = vsprintf(*write_pos, fmt, args);
*write_pos += num_written;
va_end(args);
}
//...
fprintf_to_mem(&write_pos, "Testing %d %d %d", 1, 2, 3);
fprintf_to_mem(&write_pos, "Hello world!\r\n");
I would expect that to output "Testing 1 2 3Hello world!\r\n" to huge_buffer.