does varargs offer a kind of poor man's polymorphism?

Discussion in 'C Programming' started by pete, Dec 17, 2010.

  1. pete

    pete Guest

    No doubt every other student of C has noticed this; it's new to me.

    If I declare:

    int xlate( void *, ... );

    and then define xlate( ) in several different ways (maybe all
    definitions but one are #ifdef-ed out):

    int xlate ( char *arg1 ) { ... }
    int xlate ( int arg1, char *arg2, int arg3 ) { ... }
    int xlate ( char arg1, int *arg2 ) { ... }

    and omit any mention of va_list -- never mentioning it -- in every
    definition of xlate( ); and then call xlate( ) abiding by one of its
    several definitions, it seems that every compiled version of xlate( )
    works just the way I want, at least under gcc and msvc.

    Is this relaxed, undemanding, generous compiler behavior guaranteed
    under C99?

    Thanks!

    -- Pete
     
    pete, Dec 17, 2010
    #1
    1. Advertising

  2. pete

    Seebs Guest

    On 2010-12-17, pete <> wrote:
    > Is this relaxed, undemanding, generous compiler behavior guaranteed
    > under C99?


    No, and there's been many counterexamples on real-world architectures.

    Don't do that.

    -s
    --
    Copyright 2010, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
    I am not speaking for my employer, although they do rent some of my opinions.
     
    Seebs, Dec 17, 2010
    #2
    1. Advertising

  3. pete

    pete Guest

    On Dec 16, 9:35 pm, Seebs <> wrote:
    > On 2010-12-17, pete <> wrote:
    >
    > > Is this relaxed, undemanding, generous compiler behavior guaranteed
    > > under C99?

    >
    > No, and there's been many counterexamples on real-world architectures.
    >
    > Don't do that.
    >
    > -s
    > --
    > Copyright 2010, all wrongs reversed.  Peter Seebach / ://www.seebs.net/log/<-- lawsuits, religion, and funny pictureshttp://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
    > I am not speaking for my employer, although they do rent some of my opinions.


    Peter, if it's convenient, would you please be good enough to point me
    to just any random one of these many counterexamples?

    Thanks so much!

    -- p
     
    pete, Dec 17, 2010
    #3
  4. pete

    Eric Sosman Guest

    On 12/16/2010 8:58 PM, pete wrote:
    >
    > No doubt every other student of C has noticed this; it's new to me.
    >
    > If I declare:
    >
    > int xlate( void *, ... );
    >
    > and then define xlate( ) in several different ways (maybe all
    > definitions but one are #ifdef-ed out):
    >
    > int xlate ( char *arg1 ) { ... }
    > int xlate ( int arg1, char *arg2, int arg3 ) { ... }
    > int xlate ( char arg1, int *arg2 ) { ... }


    Each of the three would have to be in a separate compilation unit,
    and at least two would have to be `static', and none of the three
    compilation units could "see" the declaration. In other words,

    1) In a single compilation unit, a name can be defined at most
    once.

    2) In a single program, a name with external linkage can refer
    to only one function, hence one function definition.

    3) In a single compilation unit, all declarations and definitions
    of a function must agree.

    > and omit any mention of va_list -- never mentioning it -- in every
    > definition of xlate( ); and then call xlate( ) abiding by one of its
    > several definitions, it seems that every compiled version of xlate( )
    > works just the way I want, at least under gcc and msvc.


    ... whatever "works just the way I want" may mean.

    > Is this relaxed, undemanding, generous compiler behavior guaranteed
    > under C99?


    You haven't described "works just the way I want," so the question
    is not well-formed. Even so, I'll venture an answer: NO. I'll also
    give the C90 answer: NO. And I'll make a guess at the C1x answer: NO.
    What part of "NO" are you having trouble understanding? (And, out of
    curiosity, why do you use "polymorphism" to describe what most people
    term either "overloading" or "Haddocks' Eyes?")

    --
    Eric Sosman
    lid
     
    Eric Sosman, Dec 17, 2010
    #4
  5. On Dec 16, 9:25 pm, Eric Sosman <> wrote:
    > (And, out of
    > curiosity, why do you use "polymorphism" to describe what most people
    > term either "overloading" or "Haddocks' Eyes?")


    Yeah. You can't do polymorphism in C (or function dispatch based on
    types) without some non-standard extension like gs's typeof,
    or maybe with user-defined tag-unions.

    BTW, what's "Haddocks' Eyes"? It sounds so tantalizingly mysterious!
     
    luser- -droog, Dec 17, 2010
    #5
  6. pete

    Eric Sosman Guest

    On 12/16/2010 10:49 PM, luser- -droog wrote:
    > On Dec 16, 9:25 pm, Eric Sosman<> wrote:
    >> (And, out of
    >> curiosity, why do you use "polymorphism" to describe what most people
    >> term either "overloading" or "Haddocks' Eyes?")

    >
    > Yeah. You can't do polymorphism in C (or function dispatch based on
    > types) without some non-standard extension like gs's typeof,
    > or maybe with user-defined tag-unions.


    The former is non-standard, but the latter need not be.

    > BTW, what's "Haddocks' Eyes"? It sounds so tantalizingly mysterious!


    GIYF.

    --
    Eric Sosman
    lid
     
    Eric Sosman, Dec 17, 2010
    #6
  7. pete

    Eric Sosman Guest

    On 12/16/2010 11:32 PM, Ered China Luin wrote:
    > [...]
    > You can pass any type through a var-args call, but get the arguments with va_arg
    > and don't lie about the type.


    Note that va_arg() must specify the *promoted* type: `double' and
    `int' instead of `float' and `short', for example. This makes trouble
    with types whose promotion rules differ from one system to another.
    For example, in

    enum TriplePlay { TINKER, EVERS, CHANCE } infielder = CHANCE;
    void func(const char *, ...);
    func ("What is the type of the second parameter?", infielder);

    The type of the second *argument* is `enum TriplePlay', which we know
    is "compatible with char, a signed integer type, or an unsigned integer
    type," at the implementation's discretion. The compatible type the
    implementation chooses may (or may not be) subject to promotion, and if
    promotable may promote to pretty much anything. So, what type should
    the va_arg() macro use to retrieve the second parameter? Different
    implementations will give different answers (and `enum TriplePlay' will
    not be among them, if that is a promotable type).

    Even `size_t' and `ptrdiff_t' are theoretically subject to this
    problem, although in practice they are usually wide enough that they
    do not promote. Still, it is possible for a Standard-conforming C to
    have `SIZE_MAX < INT_MAX', and if this happens a `size_t' argument
    will promote to an `int' parameter and `va_arg(ap, size_t)' will be
    incorrect.

    For ultimate safety in passing (possibly) promotable types to
    varargs functions, I guess you could wrap the suspect value in a
    struct or union, types that are never promoted:

    union Wrapper { enum TriplePlay payload; } carrier;
    carrier.payload = infielder;
    func ("The second parameter is a `union Wrapper'.", carrier);

    Another possibility is to pass a pointer:

    func ("The second parameter points to an `enum TriplePlay'.",
    &infielder);

    I confess, though, that I've never seen these dodges used -- not even
    by people who've previously fallen afoul of an unexpected promotion!

    --
    Eric Sosman
    lid
     
    Eric Sosman, Dec 17, 2010
    #7
  8. pete

    Seebs Guest

    On 2010-12-17, pete <> wrote:
    > Peter, if it's convenient, would you please be good enough to point me
    > to just any random one of these many counterexamples?


    Don't remember which systems, but there are systems where variadic
    functions have all arguments passed on the stack, but other functions
    typically use registers for at least some arguments, such as floating
    point values.

    -s
    --
    Copyright 2010, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
    I am not speaking for my employer, although they do rent some of my opinions.
     
    Seebs, Dec 17, 2010
    #8
  9. pete

    pete Guest

    Thanks, everyone. I appreciate all the comments and course
    corrections.

    -- pete
    ----------
    "it means just what I choose it to mean -- neither more nor less"
    -- Humpty Dumpty
     
    pete, Dec 17, 2010
    #9
  10. On Fri, 17 Dec 2010 00:48:34 -0500, Eric Sosman
    <> wrote:

    > On 12/16/2010 11:32 PM, Ered China Luin wrote:
    > > [...]
    > > You can pass any type through a var-args call, but get the arguments with va_arg
    > > and don't lie about the type.

    >
    > Note that va_arg() must specify the *promoted* type: `double' and
    > `int' instead of `float' and `short', for example. This makes trouble
    > with types whose promotion rules differ from one system to another.
    > For example, [enum which may be (compatible with) any integer type]
    > at the implementation's discretion. The compatible type the
    > implementation chooses may (or may not be) subject to promotion, and if
    > promotable may promote to pretty much anything. So, what type should


    In principle, but enums in C can never exceed the range of 'int',
    which is also normatively (though ill-definedly) 'the natural size'
    for the execution environment, so I see no good reason ever to use
    anything wider. An implementation can reasonably narrower integers,
    but they are all taken to int by the default promotions. Have you seen
    actual problems here?

    > the va_arg() macro use to retrieve the second parameter? Different
    > implementations will give different answers (and `enum TriplePlay' will
    > not be among them, if that is a promotable type).
    >
    > Even `size_t' and `ptrdiff_t' are theoretically subject to this
    > problem, although in practice they are usually wide enough that they
    > do not promote. Still, it is possible for a Standard-conforming C to
    > have `SIZE_MAX < INT_MAX', and if this happens a `size_t' argument
    > will promote to an `int' parameter and `va_arg(ap, size_t)' will be
    > incorrect.
    >

    Yeah, that one is usually okay but could be a problem.

    Similarly but without vararg, getting socklen_t to port right has
    wasted more of my time than can be justified in any sane universe.

    <snip rest>
     
    David Thompson, Dec 27, 2010
    #10
  11. On Dec 17, 5:48 am, Eric Sosman <> wrote:
    >
    >         func ("The second parameter points to an `enum TriplePlay'.",
    >               &infielder);
    >
    > I confess, though, that I've never seen these dodges used -- not even
    > by people who've previously fallen afoul of an unexpected promotion!
    >
    >

    In high-level languages you often see this

    answer = power(base = x, exponent = y)

    it means that caller can miss out parameters, and doesn't have to
    remember the order in which arguments are passed. It also gives a
    powerful clue to the reader what they mean.
    You can do the same with C varags, but I must confess I've never see
    it done.
     
    Malcolm McLean, Dec 27, 2010
    #11
  12. pete

    Mark Wooding Guest

    Malcolm McLean <> writes:

    > In high-level languages you often see this
    >
    > answer = power(base = x, exponent = y)
    >
    > You can do the same with C varags, but I must confess I've never see
    > it done.


    The X Toolkit Intrinsics (Xt) library does something rather like this,
    e.g., in XtVaCreateWidget. The Gobject system also has something
    similar, in g_object_new and friends.

    -- [mdw]
     
    Mark Wooding, Dec 27, 2010
    #12
  13. On 16 Dec 2010 19:58, pete wrote:
    > No doubt every other student of C has noticed this; it's new to me.
    >
    > If I declare:
    >
    > int xlate( void *, ... );
    >
    > and then define xlate( ) in several different ways (maybe all
    > definitions but one are #ifdef-ed out):
    >
    > int xlate ( char *arg1 ) { ... }
    > int xlate ( int arg1, char *arg2, int arg3 ) { ... }
    > int xlate ( char arg1, int *arg2 ) { ... }
    >
    > and omit any mention of va_list -- never mentioning it -- in every
    > definition of xlate( ); and then call xlate( ) abiding by one of its
    > several definitions, it seems that every compiled version of xlate( )
    > works just the way I want, at least under gcc and msvc.
    >
    > Is this relaxed, undemanding, generous compiler behavior guaranteed
    > under C99?


    No; this invokes undefined behavior. One possible result of undefined
    behavior may be doing exactly what you want--until it comes time to port
    to another implementation or demo your "working" code to your boss/customer.

    There exist implementations which pass arguments to variadic functions
    on the stack but arguments to non-variadic functions in registers, which
    is allowed by the Standard but will obviously break your code.

    S

    --
    Stephen Sprunk "God does not play dice." --Albert Einstein
    CCIE #3723 "God is an inveterate gambler, and He throws the
    K5SSS dice at every possible opportunity." --Stephen Hawking
     
    Stephen Sprunk, Dec 27, 2010
    #13
    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. Replies:
    9
    Views:
    510
    Benji
    Nov 23, 2005
  2. qvx
    Replies:
    7
    Views:
    453
  3. Andrea Crotti

    Poor man unit testing

    Andrea Crotti, Jul 22, 2010, in forum: C Programming
    Replies:
    7
    Views:
    350
    Andrea Crotti
    Jul 29, 2010
  4. Jaap Karssenberg

    conflict between man perlipc and man perlfunc !?

    Jaap Karssenberg, Jan 9, 2004, in forum: Perl Misc
    Replies:
    0
    Views:
    177
    Jaap Karssenberg
    Jan 9, 2004
  5. Replies:
    21
    Views:
    263
    Martijn Lievaart
    Mar 8, 2010
Loading...

Share This Page