problem with macro

Discussion in 'C Programming' started by Roman Mashak, Jun 18, 2005.

  1. Roman Mashak

    Roman Mashak Guest

    Hello, All!

    I would like to use this macro to substitute type of variable, but it
    doesn't work by now:

    typedef enum table_type_e {
    INT,
    FLOAT,
    DOUBLE
    } table_type_t;

    #define TYPE(t) ((t == INT) ? int :\
    (t == FLOAT) ? float :\
    (t == DOUBLE) ? double : void )

    int main()
    {
    .....
    table_type_t t;
    t = INT;
    TYPE(t) p;
    ......
    }

    I'd like 'p' be has 'int' type. But during compilation I get this error:
    parse error before "int" It points directly to "TYPE(t) p" string.
    Am I breaking the standard or making some C-specific mistake?

    PS. if it's important, I'm using gcc-3.2.2

    With best regards, Roman Mashak. E-mail:
    Roman Mashak, Jun 18, 2005
    #1
    1. Advertising

  2. Roman Mashak wrote on 18/06/05 :
    > Hello, All!
    >
    > I would like to use this macro to substitute type of variable, but it doesn't
    > work by now:
    >
    > typedef enum table_type_e {
    > INT,
    > FLOAT,
    > DOUBLE
    > } table_type_t;
    >
    > #define TYPE(t) ((t == INT) ? int :\
    > (t == FLOAT) ? float :\
    > (t == DOUBLE) ? double : void )
    >
    > int main()
    > {
    > ....
    > table_type_t t;
    > t = INT;
    > TYPE(t) p;
    > .....
    > }
    >
    > I'd like 'p' be has 'int' type. But during compilation I get this error:
    > parse error before "int" It points directly to "TYPE(t) p" string.
    > Am I breaking the standard or making some C-specific mistake?
    >
    > PS. if it's important, I'm using gcc-3.2.2
    >
    > With best regards, Roman Mashak. E-mail:


    You can't do that. The usual trick is hard coded :

    typedef enum
    {
    INT,
    FLOAT,
    DOUBLE
    }
    table_type_e;


    void f (table_type_e t)
    {
    switch (t)
    {
    case INT:
    {
    int p;
    /* <...> */
    }
    break;

    case FLOAT:
    {
    float p;
    /* <...> */
    }
    break;

    case DOUBLE:
    {
    double p;
    /* <...> */
    }
    break;
    }
    }

    int main (void)
    {
    f (INT);
    return 0;
    }

    --
    Emmanuel
    The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
    The C-library: http://www.dinkumware.com/refxc.html

    "Mal nommer les choses c'est ajouter du malheur au
    monde." -- Albert Camus.
    Emmanuel Delahaye, Jun 18, 2005
    #2
    1. Advertising

  3. Roman Mashak

    Roman Mashak Guest

    Hello!

    Actually the goal I'm chasing for is the following. I'm implementing
    function, searching elements in the array by its own algorithm. The problem
    is that array can be of different types: int, float, double, long etc. So,
    I'd prefer to implement everything in one function.

    typedef enum table_type_e {
    INT,
    FLOAT,
    DOUBLE
    } table_type_t;

    The function is declared in this wway:

    // 'tbl' is array of elements, 'key' is key of search, 'nm' - number of
    elements and 't' is a type of array I pass to function
    int m_search(void *tbl, void *key, size_t nm, table_type_t t)
    {
    ....
    }

    int main()
    {
    int tbl[5] = {1,2,3,4,5};
    int key=2;
    ...
    }

    The first problem I faced is I must make type-casting in the m_search(),
    that's why I transfer array type to it. So, if I use 'switch-case' way the
    function will be too fat :) that's why I'm interested in making some macro
    to simplify, if you say it's too hard - may be there is another way for
    type-casting in my situation?

    Thanks in advance for any help!

    With best regards, Roman Mashak. E-mail:
    Roman Mashak, Jun 18, 2005
    #3
  4. Roman Mashak

    Michael Mair Guest

    Roman Mashak wrote:
    > Hello, All!
    >
    > I would like to use this macro to substitute type of variable, but it
    > doesn't work by now:
    >
    > typedef enum table_type_e {
    > INT,
    > FLOAT,
    > DOUBLE
    > } table_type_t;
    >
    > #define TYPE(t) ((t == INT) ? int :\
    > (t == FLOAT) ? float :\
    > (t == DOUBLE) ? double : void )
    >
    > int main()
    > {
    > ....
    > table_type_t t;
    > t = INT;
    > TYPE(t) p;


    There is no generic "conditional typing" in C.

    Okay, let's see what you have got after the preprocessor ran over
    it (or, after the respective translation phase, for the nitpickers):

    TYPE(T) p;
    (T instead of t for clarity) becomes

    ((T == INT) ? int : (T == FLOAT) ? float : (T == DOUBLE) ? double :
    void ) p;

    So, you want from the preprocessor (or, before the respective
    translation phases) to analyse your code and reduce it to either
    int or float or double or void (BTW: what will you do with a "variable"
    of type void).
    If you go a step further, T could be determined at runtime by reading
    some user input. This cannot work.

    Apart from that, the conditional operator is subject to the following
    constraints:

    ,- C99, 6.5.15#2, #3 ---
    |
    | The first operand shall have scalar type.
    |
    | One of the following shall hold for the second and third operands:
    | * both operands have arithmetic type;
    | * both operands have the same structure or union type;
    | * both operands have void type;
    | * both operands are pointers to qualified or unqualified versions of
    | compatible types;
    | * one operand is a pointer and the other is a null pointer constant;
    | or
    | * one operand is a pointer to an object or incomplete type and the
    | other is a pointer to a qualified or unqualified version of void.
    `----

    So, no operand can be a _type_.
    Now, you could have the bright idea to give p as a second parameter
    to the macro. This won't work either.
    What you _can_ do is something like

    typedef struct {
    table_type_t type;
    union {
    int IntVal;
    float FltVal;
    double DblVal;
    } value;
    } alltypes_t;

    combined with a standard way to initialise variables of this type
    and a way of error handling.

    Cheers
    Michael
    > .....
    > }
    >
    > I'd like 'p' be has 'int' type. But during compilation I get this error:
    > parse error before "int" It points directly to "TYPE(t) p" string.
    > Am I breaking the standard or making some C-specific mistake?
    >
    > PS. if it's important, I'm using gcc-3.2.2
    >
    > With best regards, Roman Mashak. E-mail:
    >
    >



    --
    E-Mail: Mine is an /at/ gmx /dot/ de address.
    Michael Mair, Jun 18, 2005
    #4
  5. Roman Mashak

    Roman Mashak Guest

    Hello, Michael!
    You wrote on Sat, 18 Jun 2005 10:17:00 +0200:

    MM> So, no operand can be a _type_.
    MM> Now, you could have the bright idea to give p as a second parameter
    MM> to the macro. This won't work either.
    MM> What you _can_ do is something like

    MM> typedef struct {
    MM> table_type_t type;
    MM> union {
    MM> int IntVal;
    MM> float FltVal;
    MM> double DblVal;
    MM> } value;
    MM> } alltypes_t;

    MM> combined with a standard way to initialise variables of this type
    MM> and a way of error handling.
    Thanks for detailed explanation, but I'm not sure what I'm supposed to do
    with structure you offered? Use it as an argument for my taget function and
    pass pointer to 'alltypes_t' for the function, am I right?


    With best regards, Roman Mashak. E-mail:
    Roman Mashak, Jun 18, 2005
    #5
  6. On Sat, 18 Jun 2005 17:16:31 +0900, Roman Mashak wrote:

    > Hello!
    >
    > Actually the goal I'm chasing for is the following. I'm implementing
    > function, searching elements in the array by its own algorithm.


    C is statically typed, any particular point in the evaluation of an
    expression there is only ever one type. If you want to handle multiple
    types you need to have separate code for each type you handle. You can
    copy any type of object by treating it as an array of unsigned char, which
    is in effect what memcpy() does. Take for example the standard library
    function qsort(). It can sort arrays of any element type; it can copy
    elements internally but it can't interpret the data in the elements.
    Therefore it requires you to provide a comparison function written for the
    specific element types to do this.

    > The problem
    > is that array can be of different types: int, float, double, long etc. So,
    > I'd prefer to implement everything in one function.
    >
    > typedef enum table_type_e {
    > INT,
    > FLOAT,
    > DOUBLE
    > } table_type_t;
    >
    > The function is declared in this wway:
    >
    > // 'tbl' is array of elements, 'key' is key of search, 'nm' - number of
    > elements and 't' is a type of array I pass to function
    > int m_search(void *tbl, void *key, size_t nm, table_type_t t)
    > {
    > ...
    > }


    Your function will need to contain separate code for each of the types it
    supports. A switch statement is a reasonable way to do this.

    > int main()
    > {
    > int tbl[5] = {1,2,3,4,5};
    > int key=2;
    > ...
    > }
    >
    > The first problem I faced is I must make type-casting in the m_search(),
    > that's why I transfer array type to it. So, if I use 'switch-case' way the
    > function will be too fat :)


    What's your criterion for "too fat"?

    > that's why I'm interested in making some macro
    > to simplify, if you say it's too hard - may be there is another way for
    > type-casting in my situation?


    Macros simply expand to code which is then compiled as normal, so you
    can't do anything with a macro that you can't do without one. You might be
    able to make the source code shorter by replacing repetitive sequences of
    code with macros which expand during translation, but the object code
    won't be any smaller.

    Lawrence
    Lawrence Kirby, Jun 18, 2005
    #6
  7. Roman Mashak

    Michael Mair Guest

    Roman Mashak wrote:
    > Hello, Michael!
    > You wrote on Sat, 18 Jun 2005 10:17:00 +0200:
    >
    > MM> So, no operand can be a _type_.
    > MM> Now, you could have the bright idea to give p as a second parameter
    > MM> to the macro. This won't work either.
    > MM> What you _can_ do is something like
    >
    > MM> typedef struct {
    > MM> table_type_t type;
    > MM> union {
    > MM> int IntVal;
    > MM> float FltVal;
    > MM> double DblVal;
    > MM> } value;
    > MM> } alltypes_t;
    >
    > MM> combined with a standard way to initialise variables of this type
    > MM> and a way of error handling.
    > Thanks for detailed explanation, but I'm not sure what I'm supposed to do
    > with structure you offered? Use it as an argument for my taget function and
    > pass pointer to 'alltypes_t' for the function, am I right?


    From your other posting, <d90l8r$1f2b$>, I infer that
    you do not wish to represent one out of a number of types for which
    the above can cater but that you want to have a "template" functionality
    which works for arrays of arbitrary type.
    This is not possible -- you need separate code for every type.

    Cheers
    Michael
    --
    E-Mail: Mine is an /at/ gmx /dot/ de address.
    Michael Mair, Jun 18, 2005
    #7
    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. Dead RAM
    Replies:
    20
    Views:
    1,112
    John Harrison
    Jul 14, 2004
  2. D Senthil Kumar

    macro name from macro?

    D Senthil Kumar, Sep 20, 2003, in forum: C Programming
    Replies:
    1
    Views:
    580
    Jack Klein
    Sep 21, 2003
  3. sounak

    to get macro name from macro value

    sounak, Nov 22, 2005, in forum: C Programming
    Replies:
    17
    Views:
    502
    Mark McIntyre
    Nov 22, 2005
  4. Patrick Kowalzick
    Replies:
    5
    Views:
    471
    Patrick Kowalzick
    Mar 14, 2006
  5. Mike Manilone

    macro inside macro

    Mike Manilone, Oct 3, 2011, in forum: C Programming
    Replies:
    8
    Views:
    459
    Mike Manilone
    Oct 6, 2011
Loading...

Share This Page