How can you avoid the erroneous extraction of emptiness * of the wrong type?

Programming in C, are there any methods that can be used to avoid (or at least minimize the likelihood) of pouring the void * into the wrong pointer type by mistake? I am working on a program that analyzes several different types of CSV files and stores fields in specific data structures for processing. For example, records of one of the data files are stored in a hash table; data from another file is stored in an oriented graph.

I would like to create one basic parsing function that reads fields from a file in a record and passes each record to a function that tokens fields and stores them in the corresponding data type. Instead of creating separate parsing / tokenization functions for each file type, I wanted to create a common function for this. In my design, the calling function will pass the field record, the function pointer to the tokenizer applicable to the data file, and void * pointing to the node of the destination data structure applicable to the data file.

I want to know if there is a way to ensure that the user does not mistakenly call the parsing function with an inconsistent tokenizer / data structure. (Using a pointer to void, the compiler is certainly helpless here.) Or, if there are no such methods, are there any effective methods for handling exceptions to catch this error and prevent serious problems (for example, sigfaults)?

I want the code to be as portable as possible.

Any thoughts? I am not married to this algorithm, if someone has a better idea, I am open to it.

+4
source share
1 answer

One possibility is to create a set of very subtle wrapper functions that abstract away type safety concerns:

void foo_generic(FieldRecords *records, Parser *parser, void *dest); ... void foo_A(FieldRecords *records, A *dest) { foo_generic(records, &parse_A, dest); } void foo_B(FieldRecords *records, B *dest) { foo_generic(records, &parse_B, dest); } void foo_C(FieldRecords *records, C *dest) { foo_generic(records, &parse_C, dest); } 

Now all potentials for typos are limited to one place where errors should be easier to find due to symmetry.

If you feel particularly naughty, you can use a macro to make it easier to create these wrapper functions:

 #define FOO(T) void foo_##T(FieldRecords *records, T *dest) { \ foo_generic(records, &parse_##T, dest); \ } FOO(A) FOO(B) FOO(C) 

This minimizes the chance of typos, but increases the likelihood of confusing the debugger / IDE!

+5
source

Source: https://habr.com/ru/post/1399595/


All Articles