data types question

T

theshowmecanuck

As a matter of academic interest only, is there a way to programmatically
list the 'c' data types? I am not looking for detail, just if it is
possible, and what function could be used to accomplish it. For example:

int main void()
{
while there are more data types
{
print next data type;
}
return(0);
}


output:
int
long
float
char
etc.
 
P

Peter Nilsson

theshowmecanuck said:
As a matter of academic interest only, is there a way to programmatically
list the 'c' data types? I am not looking for detail, just if it is
possible, and what function could be used to accomplish it. For example:

int main void()

int main(void)
{
while there are more data types
{
print next data type;
}
return(0);
}

output:
int
long
float
char
etc.

[Presumably you're ruling out struct, union, pointer, array and function
types.]

There is no function to do this. You could write your own in C90, since
there are a fixed number of basic data types. You could probably write a
program which writes a program under C99, assuming any extended integer
types will be covered under the xxx_leastN_t types.

That said, why would you want to do this? Even 'academic interest' is only
useful if there's something to be derived from it.
 
G

Gordon Burditt

As a matter of academic interest only, is there a way to programmatically
I have occasionally thought about adding a type_t data type to C, which
contains the type of something, and could be used to do run-time
data typing (among other things, you could cast something to a type
specified by a type_t variable). Question: how many bits does it need?
[Presumably you're ruling out struct, union, pointer, array and function
types.]

I'm not ruling out those types, and int [2][3][4][5][6] is
different from int [3][2][4][5][6]. It's things like this that make
type_t more than a bit impractical.
There is no function to do this. You could write your own in C90, since
there are a fixed number of basic data types. You could probably write a
program which writes a program under C99, assuming any extended integer
types will be covered under the xxx_leastN_t types.

Since C does not place any upper limit on things like the maximum number
of levels of indirection on pointer to pointer to pointer ... to char
variables, there's a real problem the program would never terminate.


Another challenge related to my type_t idea: given a series of functions
that operate on a type_t, such as type_is_array(), type_is_function(),
type_is_pointer(), which tell you the characteristics of a type, and
some operators on types like type_dereference(), which returns the
type you get when you dereference its argument, and type_elementtype(),
which returns the type of the elements of an array type, write a program
which prints out a C declaration for that type, using a supplied variable
name and type_t.

You might see code like this in a simplified version that only had
to worry about basic data types and pointers to them (not arrays,
functions, structs, unions, etc.):

for (t = value; type_is_pointer(t); t = type_dereference(t)) {
printf("*");
}

Gordon L. Burditt
 
V

Victor Nazarov

Gordon said:
I have occasionally thought about adding a type_t data type to C, which
contains the type of something, and could be used to do run-time
data typing (among other things, you could cast something to a type
specified by a type_t variable). Question: how many bits does it need?
IMHO, it must be of variable length, you must invent some coding for it
to be able to get the type reading the stream of chars. (so fo ex.
type_t must be typedefed as pointer to char).
The other question is why do you want to list all types. I think that
the only use of type_t object is to set it to the type of the other
existing object. Casting to the explicitely defined type is allready
implemented. Casting to some random type is of no use.
 
G

Gordon Burditt

I have occasionally thought about adding a type_t data type to C, which
IMHO, it must be of variable length, you must invent some coding for it
to be able to get the type reading the stream of chars. (so fo ex.
type_t must be typedefed as pointer to char).
The other question is why do you want to list all types. I think that

That was the original poster. I think the list, not taking into
account implementation restrictions, is of infinite size. Even if
it's not of infinite size, if arrays of 31 dimensions are allowed,
you have something like MAXINT to the power of 31 different possible
31-dimensional arrays of char, which is still impractical to list.
the only use of type_t object is to set it to the type of the other
existing object. Casting to the explicitely defined type is allready
implemented. Casting to some random type is of no use.

You can pass a type_t and a value of that type to a varargs function.
This gives more complete information than the "printf-style string"
method, and it's more convenient. (Consider:
debug_print_any_type(typeof(foo), foo) which could, for example,
accurately print every member of a structure (with element names!
and using the names of enums if there is an enum element in the
structure) if foo is a structure, and print the correct number of
array elements if foo is an array) Given that you've got a "plug-in"
function (which some platforms support, but it's not portable) that
takes a particular set of arguments, you could construct those
arguments.

A "new varargs" function call could *AUTOMATICALLY* pass the types
of its arguments. Some people would argue that this is too much
overhead, and they may be right, which is why I'm not suggesting
that existing varargs functions be converted.

You can construct type_t's at runtime by building them up from user
input (effectively, VLA elements of structures). You can build,
then use, types (structures) from other descriptions of data
structures (e.g. from SQL database schema). You can accurately
(and, if this proposal was implemented, portably) calculate the
size of a structure containing a char, a pointer(N)-to-char (This
means N levels of indirection, N being specified at runtime), a double,
and an array of 5 ints *INCLUDING ALL THE PADDING* (along with the
temperature in Hell), and even calculate which ordering of these
gives the least amount of padding.

Gordon L. Burditt
 
V

Victor Nazarov

Gordon said:
That was the original poster. I think the list, not taking into
account implementation restrictions, is of infinite size. Even if
it's not of infinite size, if arrays of 31 dimensions are allowed,
you have something like MAXINT to the power of 31 different possible
31-dimensional arrays of char, which is still impractical to list.
I think C types are an infinit, enumeratable set. So there are an
infinit amount of types, but there *is* a method to enumerate them, so
there *is* a computable function to map any natural number to the C type.
You can pass a type_t and a value of that type to a varargs function.
This gives more complete information than the "printf-style string"
method, and it's more convenient. (Consider:
debug_print_any_type(typeof(foo), foo) which could, for example,
accurately print every member of a structure (with element names!
and using the names of enums if there is an enum element in the
structure) if foo is a structure, and print the correct number of
array elements if foo is an array) Given that you've got a "plug-in"
function (which some platforms support, but it's not portable) that
takes a particular set of arguments, you could construct those
arguments.
The Std ó Library printf functions have an advantage of compact writing
and the ability to store format strings in the files in portable
(enough) way. So your scheme hadn't any of this advantagies and besides
function prototypes store the types of their arguments. So the Modula-2
and C++ style is much more apropriate for this kind of task.
WrInt (5); WrStr("Hellow World");
And this style doesn't invole such complexities as your scheme.
You can construct type_t's at runtime by building them up from user
input (effectively, VLA elements of structures). You can build,
then use, types (structures) from other descriptions of data
structures (e.g. from SQL database schema). You can accurately
(and, if this proposal was implemented, portably) calculate the
size of a structure containing a char, a pointer(N)-to-char (This
means N levels of indirection, N being specified at runtime), a double,
and an array of 5 ints *INCLUDING ALL THE PADDING* (along with the
temperature in Hell), and even calculate which ordering of these
gives the least amount of padding.
So It's very hard to me to imaging any particular code (using only
casting and type_t objects). Give an example :). How will you use an
object of the unknown (at the time of compilation) type. And if you
willn't, then void pointer exists. Store anything you want.

But one proposal (not yours as I see) I agree with is to have a constant
to store maximum padding of C objects, to be able to write effective by
space allocators.
 
J

Jack Klein

I have occasionally thought about adding a type_t data type to C, which
contains the type of something, and could be used to do run-time
data typing (among other things, you could cast something to a type
specified by a type_t variable). Question: how many bits does it need?
[Presumably you're ruling out struct, union, pointer, array and function
types.]

I'm not ruling out those types, and int [2][3][4][5][6] is
different from int [3][2][4][5][6]. It's things like this that make
type_t more than a bit impractical.
There is no function to do this. You could write your own in C90, since
there are a fixed number of basic data types. You could probably write a
program which writes a program under C99, assuming any extended integer
types will be covered under the xxx_leastN_t types.

Since C does not place any upper limit on things like the maximum number
of levels of indirection on pointer to pointer to pointer ... to char
variables, there's a real problem the program would never terminate.


Another challenge related to my type_t idea: given a series of functions
that operate on a type_t, such as type_is_array(), type_is_function(),
type_is_pointer(), which tell you the characteristics of a type, and
some operators on types like type_dereference(), which returns the
type you get when you dereference its argument, and type_elementtype(),
which returns the type of the elements of an array type, write a program
which prints out a C declaration for that type, using a supplied variable
name and type_t.

You might see code like this in a simplified version that only had
to worry about basic data types and pointers to them (not arrays,
functions, structs, unions, etc.):

for (t = value; type_is_pointer(t); t = type_dereference(t)) {
printf("*");
}

Gordon L. Burditt

Why do you think this is so difficult or never ending? Compilers do
it all the time.
 
G

Gordon Burditt

You can construct type_t's at runtime by building them up from user
So It's very hard to me to imaging any particular code (using only
casting and type_t objects). Give an example :). How will you use an
object of the unknown (at the time of compilation) type. And if you
willn't, then void pointer exists. Store anything you want.

Write me a routine to dump a struct foobaz, using a void pointer
to it as input. I won't write the definition of struct foobaz until
after you submit and compile your code. Raw hexadecimal dumps don't
count.
But one proposal (not yours as I see) I agree with is to have a constant
to store maximum padding of C objects, to be able to write effective by
space allocators.

I'm assuming that there are also a large variety of operators on
type_t objects so you can construct your own types and heavily pick
apart existing types you are passed. It also includes the ability
to reference structure members by runtime-specified names (which
you can extract out of the type_t).

Imagine that you are writing a database. Using the schema for a
particular table, you construct a type_t for a structure corresponding
to the schema. Now you can take a void * pointer, cast it to a
pointer to this struct, dereference it, and use sizeof() on it.
Now you've got the size to allocate, WITH PADDING. You can also
access elements of this structure using the cast pointer. For
optimization, you can try all possible orders of structure members
and use the one with the least padding.

My proposal for "new varargs" (which implicitly passes the type of
the argument along with the argument) leaves open the possibility of
things you can't currently do in C:

- A version of printf() that actually CHECKS the compatability of the
format argument and the argument passed.
- A version of gets() (or scanf()) that takes an array argument,
refuses to overrun that array, and will fail if you pass it a pointer
instead.
- A version of execl() which takes an arbitrary number of strings
and DOESN'T need a NULL pointer to mark the end of the arguments.


Gordon L. Burditt
 
V

Victor Nazarov

Gordon said:
Write me a routine to dump a struct foobaz, using a void pointer
to it as input. I won't write the definition of struct foobaz until
after you submit and compile your code. Raw hexadecimal dumps don't
count.
It is imposible right now, but it is very easy using some conventions
like inheritance in OOP sence.
Imagine that you are writing a database. Using the schema for a
particular table, you construct a type_t for a structure corresponding
to the schema. Now you can take a void * pointer, cast it to a
pointer to this struct, dereference it, and use sizeof() on it.
Now you've got the size to allocate, WITH PADDING. You can also
access elements of this structure using the cast pointer. For
optimization, you can try all possible orders of structure members
and use the one with the least padding.
So your proposal is to include the hole database managment code into
every C program, and to make it the part of the C compiler. This is an
ambigous task. And the only problem is that I know very little (none)
peaple who needs it. There *is* an existing databases and they work, use
one. The object to hold type information is called SQL query.

Try to figure out what you really need. Do you want to implement
something that really requires your run-time type handling. Do you think
that the code using type_t will be simplier or smaller then that using
C++ with it's run-time type handling being developed scince 70th? Do you
think that your type_t is better than all OOP techniques?
My proposal for "new varargs" (which implicitly passes the type of
the argument along with the argument) leaves open the possibility of
things you can't currently do in C:

- A version of printf() that actually CHECKS the compatability of the
format argument and the argument passed.
Good idea but do you expect to include the code for printing every
possible C type (infinity) to a Standart library.
- A version of gets() (or scanf()) that takes an array argument,
refuses to overrun that array, and will fail if you pass it a pointer
instead.
Write some wrapers for string and scanf functions using
struct {
void *ptr;
size_t size;
};
and you are done. It's much easier then implementing general run-time
type handling.
- A version of execl() which takes an arbitrary number of strings
and DOESN'T need a NULL pointer to mark the end of the arguments.

Does ir really bother you?
 
G

Gordon Burditt

I have occasionally thought about adding a type_t data type to C, which
contains the type of something, and could be used to do run-time
data typing (among other things, you could cast something to a type
specified by a type_t variable). Question: how many bits does it need?
[Presumably you're ruling out struct, union, pointer, array and function
types.]

I'm not ruling out those types, and int [2][3][4][5][6] is
different from int [3][2][4][5][6]. It's things like this that make
type_t more than a bit impractical.
There is no function to do this. You could write your own in C90, since
there are a fixed number of basic data types. You could probably write a
program which writes a program under C99, assuming any extended integer
types will be covered under the xxx_leastN_t types.

Since C does not place any upper limit on things like the maximum number
of levels of indirection on pointer to pointer to pointer ... to char
variables, there's a real problem the program would never terminate.


Another challenge related to my type_t idea: given a series of functions
that operate on a type_t, such as type_is_array(), type_is_function(),
type_is_pointer(), which tell you the characteristics of a type, and
some operators on types like type_dereference(), which returns the
type you get when you dereference its argument, and type_elementtype(),
which returns the type of the elements of an array type, write a program
which prints out a C declaration for that type, using a supplied variable
name and type_t.

You might see code like this in a simplified version that only had
to worry about basic data types and pointers to them (not arrays,
functions, structs, unions, etc.):

for (t = value; type_is_pointer(t); t = type_dereference(t)) {
printf("*");
}

Gordon L. Burditt

Why do you think this is so difficult or never ending? Compilers do
it all the time.

Compilers don't have to represent a type in a type_t which is a single
variable with a bounded amount of memory determined at compile time.

It would be fairly easy to represent a type as a linked list, where one
node in the list might be a basic type, or "pointer to <this>", or
"array [<this>] of <that", or "function returning <this> and taking
arguments <that1>, <that2>, and <that3>". You might even manage to
have only one node for each basic type, everything else just points to
it.

However, I don't think it is reasonable that:

type_t t;

for (t = typeof(char); ; t = type_reference(t) ) {
/* do something with t */
}

(t would take on the types char, char *, char **, char ***, and so on.)

fails because of running out of memory.

Gordon L. Burditt
 
G

Gordon Burditt

Write me a routine to dump a struct foobaz, using a void pointer
It is imposible right now, but it is very easy using some conventions
like inheritance in OOP sence.

Really? How? In OOP, someone has to write the method to dump the
object. Even though inheritance can save a lot of work, if this
object has some special private data, you need code to handle that
data.
So your proposal is to include the hole database managment code into
every C program, and to make it the part of the C compiler. This is an
ambigous task. And the only problem is that I know very little (none)
peaple who needs it. There *is* an existing databases and they work, use
one. The object to hold type information is called SQL query.

Have you ever *WRITTEN* a database (in C)? You've got the schema (most
SQL queries, except those that actually create or change tables,
don't contain type information), however you represent it. It's
got, say, a 32-bit int, a 16-bit int, and a double in each record. You
have a buffer you have read a record into. Now, how do you get to
the double? There's probably some ugly casts and adding an offset
to char *, and perhaps either some handwaving about correct alignment,
or it uses memcpy() to copy it into a variable of the right type.
Yes, if you're just USING the database, you don't have to worry
about this stuff.
Try to figure out what you really need. Do you want to implement
something that really requires your run-time type handling. Do you think

No, I said up front it was impractical and required too much overhead,
especially the infinite-size type_t's and carrying around all the type
information.
that the code using type_t will be simplier or smaller then that using
C++ with it's run-time type handling being developed scince 70th? Do you
think that your type_t is better than all OOP techniques?

type_t probably violates a heck of a lot of things that OOP holds
dear. It may be the antithesis of OOP: you can have one function
which handles printing ALL the types, not one method for each type,
and it gets at all the private data for every type.

However, type_t and the related proposal will allow a function
passed a struct or pointer to struct to print out a list of all
that structure's member names and their values *WITHOUT* writing
any function (method) to deal with that particular structure. Just
the structure definition, and declaring one variable of that type
(or pointer to that type).
Good idea but do you expect to include the code for printing every
possible C type (infinity) to a Standart library.

It really isn't that hard. See that %d? Is the matching argument
an int? Nope, error. Each existing printf() conversion has only
a small number of types that should match it. A possible exception
is %p, which just might allow *ANY* pointer type to match it, or
maybe just allow void *.

Code to print every type isn't that hard, and probably isn't that
large. Is it a structure? Print each member name and member value.
Is it an array? Print each element. Is it a pointer? Print it as
a pointer. Is it an integer data type? Print it as an integer.
Using a recursive approach, it's probably not much bigger than printf().
The thing about type_t is that if it's a structure, you can find out
that it is, and you can get a list of the member names and types.

Write some wrapers for string and scanf functions using
struct {
void *ptr;
size_t size;
};
and you are done. It's much easier then implementing general run-time
type handling.

The problem with such wrappers is that you have to actively TRY to
get correct data into them.
Does ir really bother you?

No, but there are some people it bothers a lot. It's probably the same
people who expect free()ing a structure to recursively free everything
member pointers point at, even if what they point at wasn't dynamically
allocated.

Gordon L. Burditt
 
V

Victor Nazarov

I needn't anything from your suggestions. So It's your business to
implement something and prove it's usability.

My first suggestion is not to touch C language loved because its
simpleness and compact code.

The second is just to send every data of unknown type as a text with
known format (for ex. CSV).

And the third is to use string, containing full C definition of type as
a type_t object. For ex.:

typedef char *type_t;

struct sample {
char a;
double c;
int b[10];
};

int main (void)
{
struct sample a;
type_t type;

type = typeof (a);
sent (type, a); /* Some general type usage */
printf ("%s", type);
}

will output (the formating must be chosen by implementation):

struct {
char a;
double c;
int b[10];
};

in this case you can always use existing compiler code, and needn't
learn and invent some new syntax. And in addition text is very portable.
The last question is how to implement binary compatibility between
different architectures.
 

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

Forum statistics

Threads
473,756
Messages
2,569,533
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top