void types and how to use them efficiently?

C

cognacc

Hi
I have implemented a program with many different types.
Where i use void as a generic object (pointer).

I have a type i call Record

struct Record {
unsigned int RecordID;
void *fieldtype; // don't know type of field beforehand
struct Record *next_record; // i actually use TAILQ macro
};


So i have a collection of Records, that are read in from a file.
I dont know at any moment what my fieldtype could be.
A field type is another structure of an undeterminate size.
(really 2-20 datatypes (also another struct))

struct S2GD {
unsigned int xcoord;
unsigned int xcoord;
};


struct FRID {
char NAME[8]; // size of char array is also calculated from data
file entry
..
..
..
};

So when i need to manipulate these fields i have a large
swich case with about 20 different fieldtypes. determining type.
To determnine type i have a field_typename in my Record structure.

struct Record{
unsigned int RecordID;
char field_typename[5];
..
..
};

I then compare to field_typename to see what type it is.
To detect which function (function pointer) to use.
When using function pointers, i still need the switch case to choose
which function (ptr) to pass.



code from a function called assign() // not using function pointers
here
----
if ( (c = strcmp(field_name, "DSID")) == 0 )
{
DSID * field_dat_p;
field_dat_p = (DSID *)dr_data_ptr->field_ptr;
assign_dsid(field_dat_p, subfield_nr);
}
else if ( strcmp(field_name, "DSSI") == 0 )
{
DSSI * field_dat_p;
field_dat_p = (DSSI *) dr_data_ptr->field_ptr;
assign_dssi(field_dat_p, subfield_nr);
}
---

Lots of code, seems inefficient.
I need a char string to found out what field type it is (i think)
urgghh!

I thought there was way to get runtime detection of datatype, but i
couldnt get it to work.
like


I could probably solve it with another layer of indirection.
A table of types. (vtable like ?)
Or something?

NB: the field types are generated from reading the data file
so i don't know in advance what they are or what they contain.
That is the datafile has a specific section where it specifies the
datatypes.

A generic fieldtype look like

struct fieldtypename {
subfield1
..
..
subfieldN
};
where a subfield can be any type including structs.

I also looked at some code from embedded.com that implements objects
on
C, but thats overkill, i think.

Isnt there an intermediate way to do this?

When looking at the code i fill quite silly :), and think i must have
missed something
totally obvious.


regards Mic
 
B

Ben Bacarisse

cognacc said:
I have implemented a program with many different types.
Where i use void as a generic object (pointer).
So when i need to manipulate these fields i have a large
swich case with about 20 different fieldtypes. determining type.
To determnine type i have a field_typename in my Record structure.

struct Record{
unsigned int RecordID;
char field_typename[5];
..
..
};

I then compare to field_typename to see what type it is.
To detect which function (function pointer) to use.
When using function pointers, i still need the switch case to choose
which function (ptr) to pass.

I don't understand the problem you see with function pointers.

I'd represent the "type" as a pointer to an array of functions that
provide the type's behaviour. At the point where you set the
field_typename you should instead set the pointer to the functions for
that type of field.

I also looked at some code from embedded.com that implements objects
on
C, but thats overkill, i think.

Isnt there an intermediate way to do this?

You may not need a full object system. A few function pointers may be
enough but you don't describe the overall goal so it is hard to guess
how much machinery is needed.
 
C

cognacc

You may not need a full object system. A few function pointers may be
enough but you don't describe the overall goal so it is hard to guess
how much machinery is needed.

Thanks
Requirement - goals:
1. I parse all data from the data file
2. The field types are defined in the data file in the first section
(Called the data definition record (DDR))
3. the data in the data file is presented byte wise

4. "Need" a pointer to the field type to be able to manipulate it.
4.1 Get / setters functions, so they can be manipulated in anyway i
want. (auto generated functions)
(it's later mixed with C++ code). (also generate a toString function
for each type - prints all subfields)
5.?

Functionality:
1. get data from file byte data into data structures in memory
I need the field_typename read from the data file before i know what
type it is.
Then i store the Record in a list/tree container. (malloc's Record +
Field type).

Then i need to retrieve a Record from the list/tree container.
and according to type manipulate it in some way(generalized).

My way: :)
So i think it would be preferable, with general access to the field
type.
and i could then write any function I'd like without having to think
about what
type i work with, except using the given access functions to
manipulate the subfields.

But i still doesn't see how i can avoid using a switch case or
something like it to
choose which types i have to convert (cast) to.

i hope all, or most of the above makes sense.
regards mic
 
B

Ben Bacarisse

cognacc said:
Thanks
Requirement - goals:
1. I parse all data from the data file
2. The field types are defined in the data file in the first section
(Called the data definition record (DDR))
3. the data in the data file is presented byte wise

4. "Need" a pointer to the field type to be able to manipulate it.
4.1 Get / setters functions, so they can be manipulated in anyway i
want. (auto generated functions)
(it's later mixed with C++ code). (also generate a toString function
for each type - prints all subfields)
5.?

Functionality:
1. get data from file byte data into data structures in memory
I need the field_typename read from the data file before i know what
type it is.
Then i store the Record in a list/tree container. (malloc's Record +
Field type).

Then i need to retrieve a Record from the list/tree container.
and according to type manipulate it in some way(generalized).

My way: :)
So i think it would be preferable, with general access to the field
type.
and i could then write any function I'd like without having to think
about what
type i work with, except using the given access functions to
manipulate the subfields.

But i still doesn't see how i can avoid using a switch case or
something like it to
choose which types i have to convert (cast) to.

i hope all, or most of the above makes sense.
regards mic

I am not sure. I may not fully understand you objection to function
pointers, but I would use an array of function pointers specific to
the type of field.
 
C

cognacc

I am not sure.  I may not fully understand you objection to function
pointers, but I would use an array of function pointers specific to
the type of field.

I dont have have an "objection" to function pointers.
Just the example i pasted, did not use it.
But i don't see how i can choose the correct function pointer without
the field type, and that still corresponds to using some selection
code
like the switch case, right?
---
switch (field_type)
case: dsid:
behaviour = behaviour_dssi;
break;
..
} // end switch
behaviour(field_type_obj, action); // ??
---

hmm, i'm afraid i might not be explaining my self clearly.
Is there anything i should do, post more code, what is not clear
in my explannation?

Though i'm at a loss how to explain myself better..
I try and think about it, and then come back with a
better explanation of my problem.

What would the functions pointed do.
Like assign_field_values(assign_type_dsid, data_converted_string);

Where assign_type_dsid is the function pointer, and
data_converted_string is the
collected data from the data file converted to correct type(int,
double, char etc.)
to fill into the subfields.

Later on.
I want to do something ie toString() will print the value of every
subfield
in a field type.
print_record(record_pointer, func_print_type_dsid); // dssi is the
type
func_print_type_dssi is the function pointer.
or it could be.
func_print_type = func_print_type_dssi
print_record(record_pointer, func_print_type);

I still need the logic to choose the correct function to point to as
far as i can see.


Ps: also if anybody has some good C code, or know where there is
some, showing how to use the void type to deal with arbitrary types.
Ie like a library or application that uses it.(some "good"
"professional" code ),
not just a tutorial. (i looked at several already).


Thanks for the help
mic
 
B

Ben Bacarisse

cognacc said:
I dont have have an "objection" to function pointers.

I just meant I may have missed what it is about your program that
makes an array of function pointer unsuitable.
Just the example i pasted, did not use it.
But i don't see how i can choose the correct function pointer without
the field type, and that still corresponds to using some selection
code
like the switch case, right?
---
switch (field_type)
case: dsid:
behaviour = behaviour_dssi;
break;
..
} // end switch
behaviour(field_type_obj, action); // ??
---

The idea is to replace the type field with an array of function
pointers. For this to work you have to list all the tings you can do
with a record: let's just consider get and set (since you talked about
them before).

Currently you have some code that identifies (eventually) record's
type. This code the sets the type so that later you can get and set
by calling a get or set function that has a giant switch in it.

Instead of doing this you have, for each type, a static array of
function pointers one to get and one to set. Where you used to set a
code that determines the behaviour (the type code) you now set a
pointer to the functions that implement that behaviour.

I am sure you have seen this before, so I image that you have found
some reason why it is not suitable for this system.
hmm, i'm afraid i might not be explaining my self clearly.
Is there anything i should do, post more code, what is not clear
in my explannation?

Though i'm at a loss how to explain myself better..
I try and think about it, and then come back with a
better explanation of my problem.

What would the functions pointed do.
Like assign_field_values(assign_type_dsid, data_converted_string);

Where assign_type_dsid is the function pointer, and
data_converted_string is the
collected data from the data file converted to correct type(int,
double, char etc.)
to fill into the subfields.

You have to use unions (or, more clumsily, void *) when the are
differing types involved. The functions that get called (via the
pointers) are passed a record and possibly some data. These can
safely be union types (or void *s) because the function knows the real
type.
Later on.
I want to do something ie toString() will print the value of every
subfield
in a field type.
print_record(record_pointer, func_print_type_dsid); // dssi is the
type
func_print_type_dssi is the function pointer.
or it could be.
func_print_type = func_print_type_dssi
print_record(record_pointer, func_print_type);

I still need the logic to choose the correct function to point to as
far as i can see.

To print a record you do this:

struct Record rec;
/* set up/input rec */
rec.op_table[PRINT_FUNC_INDEX](&rec);

op_table is a pointer to a (the first element of) and array of
functions. The PRINT_FUNC_INDEX'th one of the these knows how to
print this record because you set up table when you foirst decided what
type of record this was.

What might help pin this down is a simple example of the types you are
dealing with and some of the actions you need to perform. Without
that it sounds all very vague.

<snip>
 
B

BGB / cr88192

cognacc said:
Hi
I have implemented a program with many different types.
Where i use void as a generic object (pointer).

I have a type i call Record

struct Record {
unsigned int RecordID;
void *fieldtype; // don't know type of field beforehand
struct Record *next_record; // i actually use TAILQ macro
};

<snip>

well, there are many ways to dynamically manage types, and each has good and
bad points, so the ideal choice ultimately depends on ones' requirements...


for my uses, I have a custom memory allocator (actually, it is a full
garbage collector as well, but this is besides the point), where an
allocation request will typically provide 2 pieces of information:
a type name (generally semantic);
the object size.

internally, a large hash table is used, and this essentially converts the
type name into a hash index (may be used directly for more
performance-critical code, but in generally it is not used that much).

this is also used for accessing info structs (per object, the info struct
can be fetched directly, since internally the type is an integer).

however, externally, it all just looks like an ordinary void pointer to an
ordinary chuck of memory, nevermind that one can later fetch the type name,
do various per-type operations, ...

this is very convinient to use from C, but it is not the highest performance
option.


another approach is what is known as tagged references, where the reference
is typically an integer-based type (32 or 64 bit integers), and where the
type is usually embedded directly into the reference (with other bits for
either holding a literal value, or referring to an in-heap object).

some people directly encode pointers into these references when referring to
objects, but personally I have found it more effective (when I use this
strategy) to instead encode an "object index" into the reference, which when
needed can then be resolved into the actual memory address of the object.

possible reasons for doing so:
simplifies things like precise GC and compacting collectors;
may only need 32 bit references on 64-bit computers (where otherwise one
would need 64 bits for a pointer-based reference);
....

though, it may involve a slight overhead when accessing an object (the need
to resolve the index to a pointer), it usually improves performance for many
other operations.


similarly, tagged references tend to be generally faster than "magic void
pointers"...

however, there is a downside:
they tend to be much less convinient to work with in C, and it may also be a
lot harder to have independent extension of the typesystem (since types
depend a lot on the tagging scheme, ... much more "centralization" is needed
to make all this work, ...).

or such...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top