Way to determine type of variable?

Discussion in 'C Programming' started by Walter L. Preuninger II, Jul 16, 2004.

  1. I would like to write a generic procedure that will take string or numeric
    variables. I can not think of a way to make this more clear except to show
    what I want.

    int main(void)
    {
    int i=7;
    char *s="/etc/filesystems";

    generic(i);
    generic(s);
    generic("Hello");
    generic(2048);
    exit(0);
    }

    should return:
    7
    /etc/filesystems
    Hello
    2048

    so...

    void generic( ???????)
    {
    ???
    }

    I have looked at sprintf, varargs etc.

    Could someone point me in the right direction?

    Thanks,

    Walter
    Walter L. Preuninger II, Jul 16, 2004
    #1
    1. Advertising

  2. Walter L. Preuninger II

    -berlin.de Guest

    Walter L. Preuninger II <> wrote:
    > I would like to write a generic procedure that will take string or numeric
    > variables. I can not think of a way to make this more clear except to show
    > what I want.


    > int main(void)
    > {
    > int i=7;
    > char *s="/etc/filesystems";


    > generic(i);
    > generic(s);
    > generic("Hello");
    > generic(2048);
    > exit(0);
    > }


    > should return:
    > 7
    > /etc/filesystems
    > Hello
    > 2048


    > so...


    > void generic( ???????)
    > {
    > ???
    > }


    > I have looked at sprintf, varargs etc.


    > Could someone point me in the right direction?


    Sorry, but there's no right direction. Types are a compile
    time concept and the type information is only used during the
    compilation and is only implicitely contained in the resulting
    executable (i.e. why certain machine instructions are used and
    not others). So at run-time the type information does not exist
    anymore and thus such generic functions are impossible - there
    is no additional type information attached to a variable once
    the code has been compiled.

    All that is left is the question why you need such generic
    functions (beside that it sometimes would be nice to have
    them) - perhaps there's a different solution to your problem.

    Regards, Jens
    --
    \ Jens Thoms Toerring ___ -berlin.de
    \__________________________ http://www.toerring.de
    -berlin.de, Jul 16, 2004
    #2
    1. Advertising

  3. "Walter L. Preuninger II" <> wrote in
    news:l589dc.q9t.ln@10.224.0.254:

    > I would like to write a generic procedure that will take string or
    > numeric variables. I can not think of a way to make this more clear
    > except to show what I want.
    >
    > int main(void)
    > {
    > int i=7;
    > char *s="/etc/filesystems";
    >
    > generic(i);
    > generic(s);
    > generic("Hello");
    > generic(2048);
    > exit(0);
    > }
    >
    > should return:
    > 7
    > /etc/filesystems
    > Hello
    > 2048
    >
    > so...
    >
    > void generic( ???????)
    > {
    > ???
    > }
    >
    > I have looked at sprintf, varargs etc.
    >
    > Could someone point me in the right direction?


    Hate to say it, but C++ is the right direction for this. This is one of
    those things, that in C, is rather clumsy to do, error prone, and doesn't
    look very nice in the end.

    --
    - Mark ->
    --
    Mark A. Odell, Jul 16, 2004
    #3
  4. "Walter L. Preuninger II" <> ÓÏÏÂÝÉÌ/ÓÏÏÂÝÉÌÁ × ÎÏ×ÏÓÔÑÈ
    ÓÌÅÄÕÀÝÅÅ: news:l589dc.q9t.ln@10.224.0.254...
    > I would like to write a generic procedure that will take string or numeric
    > variables. I can not think of a way to make this more clear except to show
    > what I want.
    >
    > int main(void)
    > {
    > int i=7;
    > char *s="/etc/filesystems";
    >
    > generic(i);
    > generic(s);
    > generic("Hello");
    > generic(2048);
    > exit(0);
    > }
    >
    > should return:
    > 7
    > /etc/filesystems
    > Hello
    > 2048
    >
    > so...
    >
    > void generic( ???????)
    > {
    > ???
    > }
    >
    > I have looked at sprintf, varargs etc.
    >
    > Could someone point me in the right direction?
    >
    > Thanks,
    >
    > Walter
    >
    >


    You'll need to implement polymorphism or use macrosses. If you really need
    this facilities, try using C++ instead. You CAN implement something like
    this in C, see http://ldeniau.home.cern.ch/ldeniau/html/oopc/oopc.html
    for example

    --
    vir
    Victor Nazarov, Jul 16, 2004
    #4
  5. Walter L. Preuninger II

    Eric Sosman Guest

    Walter L. Preuninger II wrote:
    > I would like to write a generic procedure that will take string or numeric
    > variables. I can not think of a way to make this more clear except to show
    > what I want.
    >
    > int main(void)
    > {
    > int i=7;
    > char *s="/etc/filesystems";
    >
    > generic(i);
    > generic(s);
    > generic("Hello");
    > generic(2048);
    > exit(0);
    > }
    >
    > should return:
    > 7
    > /etc/filesystems
    > Hello
    > 2048
    >
    > so...
    >
    > void generic( ???????)
    > {
    > ???
    > }
    >
    > I have looked at sprintf, varargs etc.
    >
    > Could someone point me in the right direction?


    The best you can get is something along the lines of

    enum Type { INT, STRING, /* others ... */ );
    generic(INT, i);
    generic(STRING, s);
    generic(STRING, "Hello");
    generic(INT, 2048);

    Or with a repackaging of essentially the same idea, you could get

    struct { enum Type type;
    union { int i; char *s; /* others ... */ } value;
    } args;
    args.type = INT; args.value.i = i; generic(args);
    args.type = STRING; args.value.s = s; generic(args);
    args.value.s = "Hello"; generic(args);
    args.type = INT; args.value.i = 2048; generic(args);

    Neither of these seems especially attractive, nor do any of
    the other variations I can think of. They're ugly, they're
    clumsy, and they're error-prone -- the compiler will not
    detect the mistakes in

    /* first form */
    generic(STRING, 42);

    /* second form */
    args.type = INT; args.value.s = "Boom!"; generic(args);

    The fundamental problem is that C is a statically-typed
    language, meaning that the type of every expression is fixed
    at compile time. True, <stdarg.h> (not <varargs.h>, BTW) can
    evade this requirement, but only briefly: In order to access
    the arguments corresponding to `...', you must use an expression
    whose type is known and immutable. C is not Lisp.

    --
    Eric Sosman, Jul 16, 2004
    #5
  6. Walter L. Preuninger II

    jacob navia Guest

    "Walter L. Preuninger II" <> a écrit dans le message de
    news:l589dc.q9t.ln@10.224.0.254...
    > I would like to write a generic procedure that will take string or numeric
    > variables. I can not think of a way to make this more clear except to show
    > what I want.
    >
    > int main(void)
    > {
    > int i=7;
    > char *s="/etc/filesystems";
    >
    > generic(i);
    > generic(s);
    > generic("Hello");
    > generic(2048);
    > exit(0);
    > }
    >
    > should return:
    > 7
    > /etc/filesystems
    > Hello
    > 2048
    >
    > so...
    >
    > void generic( ???????)
    > {
    > ???
    > }
    >
    > I have looked at sprintf, varargs etc.
    >
    > Could someone point me in the right direction?
    >
    > Thanks,
    >
    > Walter
    >


    This is not possible with standard C.
    Generic functions aren't part of the standard language.

    The lcc-win32 compiler implements generic functions
    exactly like you want, but it isn't standard C, i.e. generic
    functions are an *extension* of the language.

    If you do not mind using extensions go to
    http://www.cs.virginia.edu/~lcc-win32.

    Within standard C you can write a function like this:

    #define INTEGER 1
    #define STRING 2
    #define DOUBLE 3
    union data {
    int Type;
    int integer;
    double doublefloat;
    float floatfloat;
    char *string;
    // add other cases here
    };

    void generic(union data Data)
    {
    switch (Data.Type) {
    case INTEGER:
    printf("%d\n",Data.integer);
    break;
    case STRING:
    printf("%s\n",Data.string);
    break;
    // Add the other cases here
    }
    }

    int main(void)
    {
    union data Data;
    Data.integer = 7;
    Data.Type = INTEGER;
    generic(Data);
    Data.string = "/etc/path";
    Data.Type = STRING;
    generic(Data);
    Data.Type = DOUBLE;
    Data.doublefloat = 67.987;
    generic(DOUBLE,Data);
    /// etc
    }

    }
    jacob navia, Jul 16, 2004
    #6
  7. Walter L. Preuninger II

    Default User Guest

    "Walter L. Preuninger II" wrote:
    >
    > I would like to write a generic procedure that will take string or numeric
    > variables. I can not think of a way to make this more clear except to show
    > what I want.
    >
    > int main(void)
    > {
    > int i=7;
    > char *s="/etc/filesystems";
    >
    > generic(i);
    > generic(s);
    > generic("Hello");
    > generic(2048);
    > exit(0);
    > }
    >
    > should return:
    > 7
    > /etc/filesystems
    > Hello
    > 2048
    >
    > so...
    >
    > void generic( ???????)
    > {
    > ???
    > }
    >
    > I have looked at sprintf, varargs etc.
    >
    > Could someone point me in the right direction?



    Something like sprintf() is about as close as you are going to get. You
    can use a variadic function or pass in void pointers, but in any case
    you'll need to let the function know about the type.

    One way would be a typed data struct:


    struct data
    {
    void *datap;
    int type;
    };

    Then set type when the data is created.




    Brian Rodenborn
    Default User, Jul 16, 2004
    #7
  8. jacob navia wrote:
    >
    > Within standard C you can write a function like this:
    >
    > #define INTEGER 1
    > #define STRING 2
    > #define DOUBLE 3
    > union data {
    > int Type;
    > int integer;
    > double doublefloat;
    > float floatfloat;
    > char *string;
    > // add other cases here
    > };


    Uh, that doesn't look right. Shouldn't it be something
    more like:

    struct data
    {
    int Type;
    union values
    {
    int integer;
    double doubleFloat;
    float floatFloat;
    char *string
    // add other cases here
    };
    };

    If the Type is in the union, then wouldn't Type and
    integer overwrite each other?

    Drew
    Drew MacDonald, Jul 16, 2004
    #8
  9. <-berlin.de> wrote in message
    news:...
    > Walter L. Preuninger II <> wrote:


    [snip]

    > All that is left is the question why you need such generic
    > functions (beside that it sometimes would be nice to have
    > them) - perhaps there's a different solution to your problem.
    >
    > Regards, Jens
    > --
    > \ Jens Thoms Toerring ___ -berlin.de
    > \__________________________ http://www.toerring.de


    I needed a generic error printing routine, better than what perror()
    provides.

    incomplete code follows

    char *filename="X";
    char *buffer;
    int size=65536;

    file=fopen(filename,"rt");
    if (file==NULL)
    {
    xerror("fopen failed",filename);
    exit(1);
    }
    buffer=(char *)malloc(size);
    if(buffer == NULL) {
    xerror("malloc failed, size=",size);
    }

    I guess I could use sprintf to fill a buffer and print/pass that, but I
    wanted to lessen the amount of code written.

    I have written a macro for xerror that does pass argv[0], __FILE__, __LINE__
    and errno to produce
    ../test:test.c:15:fopen failed:X for the fopen example above.

    Thanks,

    Walter
    Walter L. Preuninger II, Jul 16, 2004
    #9
  10. Walter L. Preuninger II

    jacob navia Guest

    AAAAAArg!!!!

    Right!

    4 eyes see more than just two. Another proof of that old
    wisdom.

    It must be a structure with the type *outside* the union.

    Sorry about this bug!

    jacob
    jacob navia, Jul 16, 2004
    #10
  11. Walter L. Preuninger II

    jacob navia Guest

    The version I posted contained a serious error:
    The type of the union should not be stored in the
    union itself!

    Here is a corrected version.
    Sorry for this error.

    > Within standard C you can write a function like this:
    >
    > #define INTEGER 1
    > #define STRING 2
    > #define DOUBLE 3
    > struct data {

    int Type; // Type OUTSIDE the union
    union u {
    > int integer;
    > double doublefloat;
    > float floatfloat;
    > char *string;
    > // add other cases here
    > }u;
    > };
    >
    > void generic(union data Data)
    > {
    > switch (Data.Type) {
    > case INTEGER:
    > printf("%d\n",Data.u.integer);
    > break;
    > case STRING:
    > printf("%s\n",Data.u.string);
    > break;
    > // Add the other cases here
    > }
    > }
    >
    > int main(void)
    > {
    > union data Data;
    > Data.u.integer = 7;
    > Data.Type = INTEGER;
    > generic(Data);
    > Data.u.string = "/etc/path";
    > Data.Type = STRING;
    > generic(Data);
    > Data.Type = DOUBLE;
    > Data.u.doublefloat = 67.987;
    > generic(DOUBLE,Data);
    > /// etc
    > }
    >
    jacob navia, Jul 16, 2004
    #11
  12. Walter L. Preuninger II

    -berlin.de Guest

    Walter L. Preuninger II <> wrote:
    > I needed a generic error printing routine, better than what perror()
    > provides.


    > incomplete code follows


    > char *filename="X";
    > char *buffer;
    > int size=65536;


    > file=fopen(filename,"rt");
    > if (file==NULL)
    > {
    > xerror("fopen failed",filename);
    > exit(1);
    > }
    > buffer=(char *)malloc(size);
    > if(buffer == NULL) {
    > xerror("malloc failed, size=",size);
    > }


    > I guess I could use sprintf to fill a buffer and print/pass that, but I
    > wanted to lessen the amount of code written.


    I guess the cleanest way would be to add printf-like format
    information to the string you send to xerror(), e.g.

    xerror( "fopen failed for:%s", filename );
    xerror( "malloc failed: size=%ld", size );

    etc. and in xerror() you then would have

    #include <stdarg.h>

    void xerror( const char *fmt, ... )
    {
    va_list ap;

    /* Put printing argv[0], __FILE__ and __LINE__ in here */

    va_start( ap, fmt );
    vfprintf( stderr, fmt, ap );
    va_end( ap );
    }

    It doesn't cost you too much in typing and works without lots of
    complicated (and error prone) macros or extremely ugly code.

    Regards, Jens
    --
    \ Jens Thoms Toerring ___ -berlin.de
    \__________________________ http://www.toerring.de
    -berlin.de, Jul 16, 2004
    #12
  13. "Walter L. Preuninger II" <> writes:
    > I would like to write a generic procedure that will take string or numeric
    > variables. I can not think of a way to make this more clear except to show
    > what I want.
    >
    > int main(void)
    > {
    > int i=7;
    > char *s="/etc/filesystems";
    >
    > generic(i);
    > generic(s);
    > generic("Hello");
    > generic(2048);
    > exit(0);
    > }
    >
    > should return:
    > 7
    > /etc/filesystems
    > Hello
    > 2048


    By "should return", I think you mean "should print".

    > so...
    >
    > void generic( ???????)
    > {
    > ???
    > }
    >
    > I have looked at sprintf, varargs etc.


    You're asking about function overloading, which C doesn't support.
    <OT>C++ does.</OT>

    You can do something similar with variable argument lists
    (<stdarg.h>), but you have to have an initial argument specifying the
    type(s) of the following argument(s). For example, you could have
    something like

    generic(INT, i);
    generic(STRING, s);
    generic(STRING, "Hello");
    generic(INT, 2048);

    (given appropriate declarations of INT, STRING, etc.)

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
    Keith Thompson, Jul 16, 2004
    #13
  14. <-berlin.de> wrote in message
    news:...
    > Walter L. Preuninger II <> wrote:


    [snip]

    >
    > /* Put printing argv[0], __FILE__ and __LINE__ in here */
    >

    only problem here is that __FILE__ and __LINE__ represent the filename and
    line number of the source file, in which would be xerror.c and not main.c or
    what ever, but thanks for the info and I will see how I can apply it to my
    needs


    Thanks!

    Walter
    Walter L. Preuninger II, Jul 16, 2004
    #14
  15. Walter L. Preuninger II

    Malcolm Guest

    "Walter L. Preuninger II" <> wrote
    >
    > I would like to write a generic procedure that will take string or numeric
    > variables. I can not think of a way to make this more clear except to
    > show what I want.
    >
    > int main(void)
    > {
    > int i=7;
    > char *s="/etc/filesystems";
    >
    > generic(i);
    > generic(s);
    > generic("Hello");
    > generic(2048);
    > exit(0);
    > }
    >
    > should return:
    > 7
    > /etc/filesystems
    > Hello
    > 2048
    >
    > so...
    >
    > void generic( ???????)
    > {
    > ???
    > }
    >
    > I have looked at sprintf, varargs etc.
    >

    So you should know that you can write a function

    void generic(char *type, ...)

    generic("int", 123);
    generic("char *", "Hello");
    etc.

    Then in generic you decode the first argument, which tells you what to pass
    to va_arg() to get the argument. If you try to write printf() it is done in
    a similar manner, excpet that the format string uses a "%" specifier to tell
    you the argument type instead of passing a name.

    If you have any problem implementing the variable argument list, just post
    back.
    Malcolm, Jul 16, 2004
    #15
  16. Walter L. Preuninger II

    -berlin.de Guest

    Walter L. Preuninger II <> wrote:
    > <-berlin.de> wrote in message
    > news:...
    >> Walter L. Preuninger II <> wrote:


    > [snip]


    >>
    >> /* Put printing argv[0], __FILE__ and __LINE__ in here */
    >>

    > only problem here is that __FILE__ and __LINE__ represent the filename and
    > line number of the source file, in which would be xerror.c and not main.c or
    > what ever, but thanks for the info and I will see how I can apply it to my
    > needs


    Unless you have a C99 compliant compiler, allowing macros with a
    variable number of arguments, that's going to be more messy. The
    simplest approach probably would be to define

    #define AFL argv[0], __FILE__, __LINE__

    and use it as

    xerror( AFL, "File not found: %s", filename );

    and declare xerror as

    void xerror( const char *prog_name, const char *file_name, int line_number,
    const char *fmt, .... );

    That way you would get at the file name and line number without too
    much hassle (well, it's not beautiful, but it should work). And if
    you're too lazy to write that AFL stuff into code 'sed' or something
    similar can be quite useful for such mindnumbing tasks;-)

    Regards, Jens
    --
    \ Jens Thoms Toerring ___ -berlin.de
    \__________________________ http://www.toerring.de
    -berlin.de, Jul 16, 2004
    #16
  17. Walter L. Preuninger II

    Eric Sosman Guest

    Walter L. Preuninger II wrote:
    > <-berlin.de> wrote in message
    > news:...
    >
    >>Walter L. Preuninger II <> wrote:

    >
    >
    > [snip]
    >
    >
    >>/* Put printing argv[0], __FILE__ and __LINE__ in here */
    >>

    >
    > only problem here is that __FILE__ and __LINE__ represent the filename and
    > line number of the source file, in which would be xerror.c and not main.c or
    > what ever, but thanks for the info and I will see how I can apply it to my
    > needs


    If you have a C99-conforming compiler you can write
    macros with variable numbers of arguments, and that eases
    the task of adding __FILE__ and __LINE__ to an XERROR macro
    that in turn invokes the xerror() function. Failing that,
    gcc has its own pre-C99 way of writing "varargs macros."
    And if even that isn't acceptable, you can use the dodge
    described in Question 10.26 of the FAQ

    http://www.eskimo.com/~scs/C-faq/top.html

    --
    Eric Sosman, Jul 16, 2004
    #17
  18. Walter L. Preuninger II

    Sam Dennis Guest

    Walter L. Preuninger II wrote:
    ><-berlin.de> wrote:
    >>void xerror( const char *fmt, ... )
    >>{
    >> /* Put printing argv[0], __FILE__ and __LINE__ in here */

    >
    > only problem here is that __FILE__ and __LINE__ represent the filename and
    > line number of the source file, in which would be xerror.c and not main.c


    That's easily solved with a small macro wrapper for the function, which
    would substitute the file and line number for the invocation, e.g.:

    #define xerror( fmt, ... ) xerror( "%s:%d - " fmt, __FILE__, __LINE, \
    __VA_ARGS__ )

    However, this has several limitations (other than requiring C99 macros)
    so I'm sure that you'll want to try to make something better. Perhaps,
    even, something that doesn't affect the arguments to xerror...

    --
    ++acr@,ka"
    Sam Dennis, Jul 16, 2004
    #18
  19. Walter L. Preuninger II

    Eric Sosman Guest

    Sam Dennis wrote:
    > Walter L. Preuninger II wrote:
    >
    >><-berlin.de> wrote:
    >>
    >>>void xerror( const char *fmt, ... )
    >>>{
    >>>/* Put printing argv[0], __FILE__ and __LINE__ in here */

    >>
    >>only problem here is that __FILE__ and __LINE__ represent the filename and
    >>line number of the source file, in which would be xerror.c and not main.c

    >
    >
    > That's easily solved with a small macro wrapper for the function, which
    > would substitute the file and line number for the invocation, e.g.:
    >
    > #define xerror( fmt, ... ) xerror( "%s:%d - " fmt, __FILE__, __LINE, \
    > __VA_ARGS__ )
    >
    > However, this has several limitations (other than requiring C99 macros)
    > so I'm sure that you'll want to try to make something better. Perhaps,
    > even, something that doesn't affect the arguments to xerror...


    Another approach is to print the location information and
    the error-specific information with two functions instead of
    trying to do it all with one. In addition to Jens' xerror(),
    you'd also write

    void xwhere(const char *file, int line) {
    fprintf (stderr, "%s line %d: ", file, line);
    }

    Then you'd use

    #define XERROR xwhere(__FILE__, __LINE__) , xerror
    ...
    XERROR ("Can't open %s\n", filename);
    XERROR ("Supercalifragilisticexpialidocious!\n");
    XERROR ("Invalid co-ordinates (%g,%g)\n", x, y);

    You could, of course, dispense with xwhere() and call fprintf()
    directly from the macro expansion, if you can be sure that
    <stdio.h> has been included everwhere XERROR is used. And there
    are other variations, too -- but the essential idea here is to
    avoid all hassles with variable-length macro arguments by defining
    XERROR as an object-like macro with no arguments at all.

    --
    Eric Sosman, Jul 16, 2004
    #19
  20. -berlin.de writes:
    [...]
    > Unless you have a C99 compliant compiler, allowing macros with a
    > variable number of arguments, that's going to be more messy. The
    > simplest approach probably would be to define
    >
    > #define AFL argv[0], __FILE__, __LINE__
    >
    > and use it as
    >
    > xerror( AFL, "File not found: %s", filename );


    If it refers to argv[0], you can only use it within main() (assuming
    the usual declarations).

    You can have main() save the value of argv[0] to a global variable and
    refer to that variable in the AFL macro.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
    Keith Thompson, Jul 16, 2004
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. tshad

    Determine a session variable type

    tshad, Feb 20, 2006, in forum: ASP .Net
    Replies:
    1
    Views:
    2,887
    =?Utf-8?B?YnJpYW5zW01DU0Rd?=
    Feb 20, 2006
  2. Gernot Frisch

    how to determine type-type?

    Gernot Frisch, Jan 12, 2005, in forum: C++
    Replies:
    3
    Views:
    391
    Ulrich Achleitner
    Jan 13, 2005
  3. Replies:
    4
    Views:
    426
    Magnus Lycka
    Aug 19, 2005
  4. Replies:
    3
    Views:
    263
    Roedy Green
    Sep 15, 2007
  5. Ramon F Herrera
    Replies:
    1
    Views:
    74
    Thomas 'PointedEars' Lahn
    May 13, 2009
Loading...

Share This Page