Determining Variable type

  • Thread starter Schraalhans Keukenmeester
  • Start date
S

Schraalhans Keukenmeester

I have some C functions (with variable length argument lists) that use
void pointers as arguments.

Is there a way to determine at runtime what type of parameter is
actually passed on to the function? PHP and my oldskool turbopascal
provide a typeof() function, but my C compiler (gcc 3.4.1) does not seem
to provide this function. Perhaps someone crafted a library with some
smart code able to inspect the variable passed to a certain function?

I am aware if such a function exists it may well be platform/compiler
dependent. My primary interest lies with Linux on Intel platforms, C
compilers 3.x or 4.x

Thanks in advance
Sh.
 
W

Walter Roberson

I have some C functions (with variable length argument lists) that use
void pointers as arguments.
Is there a way to determine at runtime what type of parameter is
actually passed on to the function?

No, not in standard C.

Perhaps someone crafted a library with some
smart code able to inspect the variable passed to a certain function?
I am aware if such a function exists it may well be platform/compiler
dependent. My primary interest lies with Linux on Intel platforms, C
compilers 3.x or 4.x

Well, if you are willing to make it that specific and distinctly
non-portable, then what you do is open the executable as a file, and
grot through the symbol tables in the debugging information, and
if you are lucky the address that has been passed to you is that of
a static variable (or function) that you can match against... possibly
dead-ending there.

But there is, in general, simply no way to do what you are asking
in C, no matter how smart the library. Consider a union: by
definition in C, the addresses of the members all start at the
same memory location and the void* of all of those are the same.
union { int X; float Y } Z -- then (void*) &Z.X is the same
as (void*) &Z.Y (or at least will "compare equal".)

Address equivilence of void* is used routinely in C, as it is
fundamental to the use of malloc().
 
M

Morris Dovey

Schraalhans Keukenmeester (in [email protected])
said:

| I have some C functions (with variable length argument lists) that
| use void pointers as arguments.
|
| Is there a way to determine at runtime what type of parameter is
| actually passed on to the function? PHP and my oldskool turbopascal
| provide a typeof() function, but my C compiler (gcc 3.4.1) does not
| seem to provide this function. Perhaps someone crafted a library
| with some smart code able to inspect the variable passed to a
| certain function?
|
| I am aware if such a function exists it may well be
| platform/compiler dependent. My primary interest lies with Linux on
| Intel platforms, C compilers 3.x or 4.x

The easiest way would probably be to make the first parameter the
pointer to a string that describes the remaining parameters - like
printf, only more simple.
 
S

Schraalhans Keukenmeester

Walter said:
No, not in standard C.



Well, if you are willing to make it that specific and distinctly
non-portable, then what you do is open the executable as a file, and
grot through the symbol tables in the debugging information, and
if you are lucky the address that has been passed to you is that of
a static variable (or function) that you can match against... possibly
dead-ending there.

But there is, in general, simply no way to do what you are asking
in C, no matter how smart the library. Consider a union: by
definition in C, the addresses of the members all start at the
same memory location and the void* of all of those are the same.
union { int X; float Y } Z -- then (void*) &Z.X is the same
as (void*) &Z.Y (or at least will "compare equal".)

Address equivilence of void* is used routinely in C, as it is
fundamental to the use of malloc().
Thanks for your quick reply Walter, I feared this outcome already. I
don't intend on pushing my luck inspecting executables and 'possibly'
having a usable result.

I read up on variable length argument lists and now see the
impossibility, as well as the rationale behind how (e.g.) printf() works.
Can't have it all. Having void pointers and strongly typed vars to begin
with is a blessing in itself.

Kindest,
Sh.
 
S

Schraalhans Keukenmeester

Morris said:
Schraalhans Keukenmeester (in [email protected])
said:

| I have some C functions (with variable length argument lists) that
| use void pointers as arguments.
|
| Is there a way to determine at runtime what type of parameter is
| actually passed on to the function? PHP and my oldskool turbopascal
| provide a typeof() function, but my C compiler (gcc 3.4.1) does not
| seem to provide this function. Perhaps someone crafted a library
| with some smart code able to inspect the variable passed to a
| certain function?
|
| I am aware if such a function exists it may well be
| platform/compiler dependent. My primary interest lies with Linux on
| Intel platforms, C compilers 3.x or 4.x

The easiest way would probably be to make the first parameter the
pointer to a string that describes the remaining parameters - like
printf, only more simple.

--
Morris Dovey
DeSoto Solar
DeSoto, Iowa USA
http://www.iedu.com/DeSoto
I just ran into the following that may be of interest to others, it
surely helps me in some ways...

Link: http://www.ddj.com/dept/cpp/184401956

Summary:
gcc has a (nonstandard C) way of 'knowing' what type of var is used, by
means of the typeof() operator:

int i;
typeof(i) j; //declares a variable j with the same type as i

Not exactly what I was looking for, but still I may be able to put it to
use.

Just thought I'd let you know...
Regards
Sh.
 
G

Gordon Burditt

I just ran into the following that may be of interest to others, it
surely helps me in some ways...

Link: http://www.ddj.com/dept/cpp/184401956

Summary:
gcc has a (nonstandard C) way of 'knowing' what type of var is used, by
means of the typeof() operator:

int i;
typeof(i) j; //declares a variable j with the same type as i

But if you have a function with a parameter:

int unc(void *p)
{
/* typeof(p) here is *ALWAYS* void * in gcc, regardless of */
/* what argument is passed to unc() */
}
Not exactly what I was looking for, but still I may be able to put it to
use.

C doesn't have run-time-variable typing, with the exception of
C99 variable-size arrays, and even in that case, the size isn't
passed with the array as a function argument unless you pass it
explicitly.
 
A

Ancient_Hacker

There's no really good way to do this, as C wasnt intended to ever do
anything in this realm.
Yes, there are the vararg macros, but they're somewhat complex to use
properly.

What I'd do is write a little preprocessor, about a 7-line program in
Perl would do it, one that would take input like this:

int i; float xx; double xx;

callwithlooseargs( i, x, xx, "nice args, eh?" ); /*<> i f d s
<>*/

and generate this:

callwithlooseargs_int( i, );
callwithlooseargs_float( x );
callwithlooseargs_double( xx );
callwithlooseargs_string( "nice args, eh?" );

.... then it's up to you to supply those functions.
 
K

Keith Thompson

Ancient_Hacker said:
There's no really good way to do this, as C wasnt intended to ever do
anything in this realm.

To do what? Please quote context.
Yes, there are the vararg macros, but they're somewhat complex to use
properly.

What I'd do is write a little preprocessor, about a 7-line program in
Perl would do it, one that would take input like this:

int i; float xx; double xx;

callwithlooseargs( i, x, xx, "nice args, eh?" ); /*<> i f d s
<>*/

and generate this:

callwithlooseargs_int( i, );
callwithlooseargs_float( x );
callwithlooseargs_double( xx );
callwithlooseargs_string( "nice args, eh?" );

... then it's up to you to supply those functions.

So your "little preprocessor" can determine the type of each argument
and generate the appropriate code?

How is it going to handle things like this?

42
42 + 3.0
42ULL
rand()
arr
struct_obj->foo[0]->bar[1]

I don't believe you can do this in general with a 7-line Perl program
(unless you have *very* long lines). To handle this correctly in all
cases, you really need a complete C parser and semantic analyzer --
basically a full C compiler except for code generation.

And none of it is really necessary. Presumably when you write a call
to your function, you know the types of the arguments. Just make your
"callwithlooseargs" a variadic function (using <stdarg.h>), and define
a mechanism to allow the caller to specify the types of the arguments.
For example, you might precede each argument with something that
specifies its type:

enum arg_type { ARG_INT, ARG_FLOAT, ARG_DOUBLE, ARG_STRING };
void callwithlooseargs(enum arg_type first_type, ...);
...
callwithlooseargs(ARG_INT, i,
ARG_FLOAT, x,
ARG_DOUBLE, xx,
ARG_STRING, "nice args, eh?");

Since <stdarg.h> requires one non-variadic function, you need to treat
the first argument specially (unless you have one or more fixed
arguments anyway). Processing the arguments with va_start, va_arg,
and va_end is fairly straightforward.
 
C

Chris Torek

Ancient_Hacker said:
callwithlooseargs( i, x, xx, "nice args, eh?" ); /*<> i f d s <>*/ [fed through a script to ...]
and generate this:

callwithlooseargs_int( i, );
callwithlooseargs_float( x );
callwithlooseargs_double( xx );
callwithlooseargs_string( "nice args, eh?" );

... then it's up to you to supply those functions.

So your "little preprocessor" can determine the type of each argument
and generate the appropriate code?

I think (although I am just guessing) that the intent here is to
use the "<>" comment to supply the types.

This is (at least arguably) more efficient than having the function
pluck them out of type arguments with said:
... [using stdarg.h,] you might precede each argument with
something that specifies its type:

enum arg_type { ARG_INT, ARG_FLOAT, ARG_DOUBLE, ARG_STRING };
void callwithlooseargs(enum arg_type first_type, ...);
...
callwithlooseargs(ARG_INT, i,
ARG_FLOAT, x,
ARG_DOUBLE, xx,
ARG_STRING, "nice args, eh?");

You will need a count of arguments (kind of error-prone, in my
opinion) or a "terminator type" (ARG_END or some such).
Since <stdarg.h> requires one non-variadic function, you need to treat
the first argument specially (unless you have one or more fixed
arguments anyway). Processing the arguments with va_start, va_arg,
and va_end is fairly straightforward.

But it does add run-time overhead, which the preprocessor avoids.
On the other hand, preprocessing one call into four adds runtime
call overhead, which the variable-argument list technique avoids.
The relative speed of the two techniques is going to be rather
architecture-dependent; unless/until tested during an optimization
phase, I would write whichever one is easier to get right.
 
K

Keith Thompson

Chris Torek said:
callwithlooseargs( i, x, xx, "nice args, eh?" ); /*<> i f d s <>*/ [fed through a script to ...]
and generate this:

callwithlooseargs_int( i, );
callwithlooseargs_float( x );
callwithlooseargs_double( xx );
callwithlooseargs_string( "nice args, eh?" );

... then it's up to you to supply those functions.

So your "little preprocessor" can determine the type of each argument
and generate the appropriate code?

I think (although I am just guessing) that the intent here is to
use the "<>" comment to supply the types.

Ok, that's probably a good guess.
This is (at least arguably) more efficient than having the function
pluck them out of type arguments with said:
... [using stdarg.h,] you might precede each argument with
something that specifies its type:

enum arg_type { ARG_INT, ARG_FLOAT, ARG_DOUBLE, ARG_STRING };
void callwithlooseargs(enum arg_type first_type, ...);
...
callwithlooseargs(ARG_INT, i,
ARG_FLOAT, x,
ARG_DOUBLE, xx,
ARG_STRING, "nice args, eh?");

You will need a count of arguments (kind of error-prone, in my
opinion) or a "terminator type" (ARG_END or some such).

You're right, of course.
But it does add run-time overhead, which the preprocessor avoids.
On the other hand, preprocessing one call into four adds runtime
call overhead, which the variable-argument list technique avoids.
The relative speed of the two techniques is going to be rather
architecture-dependent; unless/until tested during an optimization
phase, I would write whichever one is easier to get right.

Indeed. Using a custom preprocessor to generate code is often useful,
but in this case I think it's more trouble than it's worth.

If it makes sense to *generate* calls to callwithlooseargs_int,
callwithlooseargs_float, et al, then IMHO, it makes sense just to
write calls to those functions directly.
 

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,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top