Writing a function that changes an unknown-type numeric variable

Discussion in 'C Programming' started by pozz, Jul 19, 2006.

  1. pozz

    pozz Guest

    In my software, there are some variables that represents some settings.
    They usually are numerical variables: unsigned char (0..255),
    signed char (-127..128), unsigned int (0..65535), signed int (-32767..32768).

    I want to write a generic C function that changes the value of one parameter.
    For example, a function that takes a pointer to the variable and increments
    it by one. Of course, the function doesn't know the variable type (unsigned
    char, signed char, and so on).

    I thought to solve this problem in two ways, but I don't like them.

    The first solution is to create a struct with 4 different pointers where
    only one of that is not NULL.

    struct {
    unsigned char *p_uchar;
    signed char *p_schar;
    unsigned int *p_uint;
    signed int *p_sint;
    ...
    } param;

    But I will lost many RAM space and the incrementing function will be poor
    optimized.

    if( p_uchar )
    *p_uchar++;
    else if( p_schar )
    *p_schar++;
    else if( p_uint )
    *p_uint++;
    else if( p_sint )
    *p_sint++;


    The other solution is to use a member of the struct to identify the type of
    the variable and using void pointer for the variable.

    #define PARAMTYPE_UCHAR 1
    #define PARAMTYPE_SCHAR 2
    #define PARAMTYPE_UINT 3
    #define PARAMTYPE_SINT 4
    struct {
    int type;
    void *p_value;
    ...
    };

    In this way I will allocate less space than before but the incrementing function
    is low optimized.

    if( type==PARAMTYPE_UCHAR )
    (*(unsigned char *)p_value)++;
    else if( type==PARAMTYPE_SCHAR )
    (*(signed char *)p_value)++;
    ....


    I wonder that a different and more elegant solution there is.
    I think to the printf() function. I pass int and char with %d parameter
    and the printf() works well, but it doesn't know the exact type of
    the variable.
    Maybe the only problem is with unsigned numerical variables that want
    the %u parameter, I think.
     
    pozz, Jul 19, 2006
    #1
    1. Advertising

  2. In article <GUtvg.46289$>,
    pozz <> wrote:
    >I want to write a generic C function that changes the value of one parameter.
    >For example, a function that takes a pointer to the variable and increments
    >it by one. Of course, the function doesn't know the variable type (unsigned
    >char, signed char, and so on).



    >In this way I will allocate less space than before but the incrementing function
    >is low optimized.


    >if( type==PARAMTYPE_UCHAR )
    > (*(unsigned char *)p_value)++;
    >else if( type==PARAMTYPE_SCHAR )
    > (*(signed char *)p_value)++;
    >...


    Try a switch() statement: at worst it will expand in to a chain of
    if/else, and the optimizer might be able to do much better than that.

    Alternately, try something like,

    void increment_uchar( void *p_value ) { *(unsigned char *)p_value)++ };
    void increment_schar( void *p_value ) { *(signed char *)p_value)++ };
    [...]

    Then you have a table of increment functions, and use

    increment_functions[type](p_value);
    --
    "No one has the right to destroy another person's belief by
    demanding empirical evidence." -- Ann Landers
     
    Walter Roberson, Jul 19, 2006
    #2
    1. Advertising

  3. pozz

    Ben Pfaff Guest

    pozz <> writes:

    > if( p_uchar )
    > *p_uchar++;


    You mean (*p_uchar)++;

    [...]

    > The other solution is to use a member of the struct to identify the type of
    > the variable and using void pointer for the variable.
    >
    > #define PARAMTYPE_UCHAR 1
    > #define PARAMTYPE_SCHAR 2
    > #define PARAMTYPE_UINT 3
    > #define PARAMTYPE_SINT 4
    > struct {
    > int type;
    > void *p_value;
    > ...
    > };


    struct tag {
    int type;
    union {
    unsigned char *uc;
    signed char *sc;
    unsigned int *ui;
    signed int *si;
    } p;
    };

    switch (v->type) {
    case PARAMTYPE_UCHAR:
    (*v->p.uc)++;
    break;
    case PARAMTYPE_SCHAR:
    (*v->p.sc)++;
    break;
    case PARAMTYPE_UINT:
    (*v->p.ui)++;
    break;
    case PARAMTYPE_SINT:
    (*v->p.si)++;
    break;
    }

    Actually, do you really need pointers? If not, you can do this:

    struct tag {
    int type;
    union {
    unsigned char uc;
    signed char sc;
    unsigned int ui;
    signed int si;
    } p;
    };

    switch (v->type) {
    case PARAMTYPE_UCHAR:
    v->p.uc++;
    break;
    case PARAMTYPE_SCHAR:
    v->p.sc++;
    break;
    case PARAMTYPE_UINT:
    v->p.ui++;
    break;
    case PARAMTYPE_SINT:
    v->p.si++;
    break;
    }

    --
    int main(void){char p[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.\
    \n",*q="kl BIcNBFr.NKEzjwCIxNJC";int i=sizeof p/2;char *strchr();int putchar(\
    );while(*q){i+=strchr(p,*q++)-p;if(i>=(int)sizeof p)i-=sizeof p-1;putchar(p\
    );}return 0;}
     
    Ben Pfaff, Jul 19, 2006
    #3
  4. pozz

    pozz Guest

    Ben Pfaff ha scritto:
    > struct tag {
    > int type;
    > union {
    > unsigned char *uc;
    > signed char *sc;
    > unsigned int *ui;
    > signed int *si;
    > } p;
    > };


    I don't want to use union because I must use const variables that are
    stored in a FLASH memory (microcontroller architecture) and not in RAM
    that is small. I must initialize that const variables but I have an old
    compiler and I can't initialize the members of a union (only C99 can do
    that, I think).

    Anyway, your example is very similar to the following:

    struct {
    int type;
    void *p_value;
    } p;

    Or not?
     
    pozz, Jul 19, 2006
    #4
  5. pozz

    Ben Pfaff Guest

    pozz <> writes:

    > Ben Pfaff ha scritto:
    >> struct tag {
    >> int type;
    >> union {
    >> unsigned char *uc;
    >> signed char *sc;
    >> unsigned int *ui;
    >> signed int *si;
    >> } p;
    >> };

    >
    > I don't want to use union because I must use const variables that are
    > stored in a FLASH memory (microcontroller architecture) and not in RAM
    > that is small. I must initialize that const variables but I have an old
    > compiler and I can't initialize the members of a union (only C99 can do
    > that, I think).


    Hmm. Well, that's rough, I guess.

    > Anyway, your example is very similar to the following:
    >
    > struct {
    > int type;
    > void *p_value;
    > } p;


    It avoids the need for casts or wordy implicit conversions, but
    the effect is similar.
    --
    Bite me! said C.
     
    Ben Pfaff, Jul 19, 2006
    #5
  6. pozz wrote:
    > In my software, there are some variables that represents some settings.
    > They usually are numerical variables: unsigned char (0..255),
    > signed char (-127..128), unsigned int (0..65535), signed int (-32767..32768).
    >
    > I want to write a generic C function that changes the value of one parameter.
    > For example, a function that takes a pointer to the variable and increments
    > it by one. Of course, the function doesn't know the variable type (unsigned
    > char, signed char, and so on).


    You can make use of some somewhat fancy macros to do the right thing.
    That way there's no long chain of tests at run-time.
    Something very close to:

    #define DefVar(Name,Type ) typedef Type Name##_Type; Name##_Type
    Name;

    #define Increment( Name ) (( Name##_Type * ) (&Name) ) ++
     
    Ancient_Hacker, Jul 19, 2006
    #6
  7. pozz

    Eric Sosman Guest

    Ancient_Hacker wrote On 07/19/06 14:39,:
    > pozz wrote:
    >
    >>In my software, there are some variables that represents some settings.
    >>They usually are numerical variables: unsigned char (0..255),
    >>signed char (-127..128), unsigned int (0..65535), signed int (-32767..32768).
    >>
    >>I want to write a generic C function that changes the value of one parameter.
    >>For example, a function that takes a pointer to the variable and increments
    >>it by one. Of course, the function doesn't know the variable type (unsigned
    >>char, signed char, and so on).

    >
    >
    > You can make use of some somewhat fancy macros to do the right thing.
    > That way there's no long chain of tests at run-time.
    > Something very close to:
    >
    > #define DefVar(Name,Type ) typedef Type Name##_Type; Name##_Type
    > Name;
    >
    > #define Increment( Name ) (( Name##_Type * ) (&Name) ) ++


    If I understand your intent, this would be used as

    DefVar(fred,int)
    DefVar(ethel,short)
    ...
    Increment(fred);
    Increment(ethel);

    expanding to

    typedef int fred_Type;
    fred_Type fred;
    typedef short ethel_Type;
    ethel_Type ethel;
    ...
    ((fred_Type *)(&fred))++;
    ((ethel_Type *)(&ethel))++;

    Have I got it? If so, I don't see how this improves on

    int fred;
    short ethel;
    ...
    fred++;
    ethel++;

    (In fact, it has the appearance of a disimprovement.) Would
    you mind explaining the benefits, or explaining what I've
    overlooked?

    --
     
    Eric Sosman, Jul 19, 2006
    #7

  8. > (In fact, it has the appearance of a disimprovement.) Would
    > you mind explaining the benefits, or explaining what I've
    > overlooked?



    The original poster wanted a "function" to increment an arbitrary
    variable. My humble macro does that, with considerably less run-time
    overhead. Whopee.

    Although now looking back, it may be that he just has a void * pointer
    coming in, in which case this macro is not quite the ticket.

    Since the exact original intent isnt clear the best solution is still
    up in the air.

    Yet another way: If you can segregate the variables by size, then you
    can key off the address:

    if( Ptr_To_Var >= &Chr_Base && Ptr_To_Var < &Int_Base ) ((uchar *)
    Ptr_To_Var) ++
    else
    if( Ptr_To_Var >= &Int_Base && Ptr_To_Var < &Long_Base ) ((int *)
    Ptr_To_Var) ++
    else
    if( Ptr_To_Var >= &Long_Base && Ptr_To_Var < &End_Vars ) ((long int *)
    Ptr_To_Var)
    else { // impossible address }
     
    Ancient_Hacker, Jul 19, 2006
    #8
  9. pozz

    Jack Klein Guest

    On Wed, 19 Jul 2006 17:23:50 GMT, pozz <>
    wrote in comp.lang.c:

    > In my software, there are some variables that represents some settings.
    > They usually are numerical variables: unsigned char (0..255),
    > signed char (-127..128), unsigned int (0..65535), signed int (-32767..32768).
    >
    > I want to write a generic C function that changes the value of one parameter.
    > For example, a function that takes a pointer to the variable and increments
    > it by one. Of course, the function doesn't know the variable type (unsigned
    > char, signed char, and so on).
    >
    > I thought to solve this problem in two ways, but I don't like them.
    >
    > The first solution is to create a struct with 4 different pointers where
    > only one of that is not NULL.
    >
    > struct {
    > unsigned char *p_uchar;
    > signed char *p_schar;
    > unsigned int *p_uint;
    > signed int *p_sint;
    > ...
    > } param;
    >
    > But I will lost many RAM space and the incrementing function will be poor
    > optimized.
    >
    > if( p_uchar )
    > *p_uchar++;
    > else if( p_schar )
    > *p_schar++;
    > else if( p_uint )
    > *p_uint++;
    > else if( p_sint )
    > *p_sint++;
    >
    >
    > The other solution is to use a member of the struct to identify the type of
    > the variable and using void pointer for the variable.
    >
    > #define PARAMTYPE_UCHAR 1
    > #define PARAMTYPE_SCHAR 2
    > #define PARAMTYPE_UINT 3
    > #define PARAMTYPE_SINT 4
    > struct {
    > int type;
    > void *p_value;
    > ...
    > };
    >
    > In this way I will allocate less space than before but the incrementing function
    > is low optimized.
    >
    > if( type==PARAMTYPE_UCHAR )
    > (*(unsigned char *)p_value)++;
    > else if( type==PARAMTYPE_SCHAR )
    > (*(signed char *)p_value)++;
    > ...
    >
    >
    > I wonder that a different and more elegant solution there is.
    > I think to the printf() function. I pass int and char with %d parameter
    > and the printf() works well, but it doesn't know the exact type of
    > the variable.
    > Maybe the only problem is with unsigned numerical variables that want
    > the %u parameter, I think.


    The real question is WHY you want to do this. I see from a later post
    that you are talking about "const" objects in an embedded system, but
    you can't reliably change const objects.

    You should explain the real problem that you are trying to solve, and
    not just ask for help with what appears to be a rather clumsy solution
    you are trying to kludge. There is probably a much better approach to
    do what you really need to accomplish.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://c-faq.com/
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
     
    Jack Klein, Jul 20, 2006
    #9
    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. Kapt. Boogschutter
    Replies:
    7
    Views:
    468
    Kapt. Boogschutter
    Jun 20, 2004
  2. Replies:
    5
    Views:
    943
    X-Centric
    Jun 30, 2005
  3. darrel
    Replies:
    4
    Views:
    825
    darrel
    Jul 19, 2007
  4. jobs

    int to numeric numeric(18,2) ?

    jobs, Jul 21, 2007, in forum: ASP .Net
    Replies:
    2
    Views:
    968
    =?ISO-8859-1?Q?G=F6ran_Andersson?=
    Jul 22, 2007
  5. Vincent Arnoux
    Replies:
    1
    Views:
    248
    Arnaud Bergeron
    Aug 11, 2006
Loading...

Share This Page