Calling a function with a literal list of strings?

Discussion in 'C Programming' started by Joakim Hove, Jul 31, 2007.

  1. Joakim Hove

    Joakim Hove Guest

    Hello,

    I have a function like this:


    /* It actually does something else .... */
    void func (int size, const char ** string_list) {
    int i;
    for (i=0; i < size; i++)
    printf("String number %d: %s \n",i,string_list);
    }

    And would like to (be able) to call it with a literal list of strings,
    something like:

    func(3 , {"String1" , "Hello", "The last string ..."});

    Is that possible? I have tried various casts like (const char **),
    (const char [3][]) and (const char [3]*) but to no avail. I am using
    gcc with std=gnu99, i.e. I am more than happy to accept C99 features.

    Thank you - Joakim Hove
    Joakim Hove, Jul 31, 2007
    #1
    1. Advertising

  2. Joakim Hove

    Chris Torek Guest

    In article <>
    Joakim Hove <> wrote:
    >I have a function like this:
    >
    >/* It actually does something else .... */
    >void func (int size, const char ** string_list) {
    > int i;
    > for (i=0; i < size; i++)
    > printf("String number %d: %s \n",i,string_list);
    >}
    >
    >And would like to (be able) to call it with a literal list of strings,
    >something like:
    >
    > func(3 , {"String1" , "Hello", "The last string ..."});
    >
    >Is that possible? ... I am more than happy to accept C99 features.


    If it were more complicated you might be out of luck, but because
    C's string literals are kind of funny and sort-of-primitive, you
    are in luck:

    void f(void) {
    func(3, (const char *[]){"1", "2", "3"});
    /* you can put in the array size too: (const char *[3]) */
    }

    >I have tried various casts like (const char **),
    >(const char [3][]) and (const char [3]*) but to no avail.


    The thing in front of the brace list *looks* exactly like a cast,
    but is not actually a cast. Instead, it is the type-specifier
    part of a "compound literal".

    Because the call to func() is within a block (all function calls
    in C are always inside a block -- you cannot call a function
    outside the outermost block of some other function), the object
    created by such a call has automatic duration. In practice, this
    means you get runtime code to create the array. You may get
    slightly better performance if you just give in and create an
    actual object, which you can then make "static":

    void f(void) {
    static const char *arg[] = {"1", "2", "3"};
    func(3, arg);
    }

    In practice, this eliminates the runtime code: the array is
    created at compile-time and exists before main() even gets
    called. (In theory, the object could be created exactly once
    when f() got called, since you would not be able to tell that
    this happened. But only in theory is theory equivalent to
    practice. :) )

    Of course, if you do this, you can also automatically count the
    number of elements in the array:

    #define NELEM(array) (sizeof array / sizeof *(array))
    void f(void) {
    static const char *arg[] = {"1", "2", "3"};
    func(NELEM(arg), arg);
    }

    and of course all of this now works in C89. The only drawback is
    that you must invent a name for each call, and the initialization
    tends to move away from the call:

    void f(void) {
    static const char *argsA[] = {"1", "2", "3"};
    static const char *argsB[] = {"Hello", "world"};

    func(NELEM(argsA), argsA);
    func(NELEM(argsB), argsB);
    }

    If you resort to C99's "declare anywhere" and variable argument
    macros, you can solve both of those with a macro, provided you are
    willing to require that each call be on a separate line:

    #define PASTE(x, y) x##y
    #define XPASTE(x, y) PASTE(x, y)
    #define DOIT(...) \
    static const char *XPASTE(args, __LINE__)[] = __VA_ARGS__; \
    func(NELEM(XPASTE(args, __LINE__)), XPASTE(args, __LINE__))

    (Here the PASTE and XPASTE auxiliary macros cause __LINE__ to get
    expanded before token-pasting, and __VA_ARGS__ extracts what the
    preprocessor sees as multiple arguments, since the comma that
    separates the initializers is not protected by parentheses.)
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://web.torek.net/torek/index.html
    Reading email is like searching for food in the garbage, thanks to spammers.
    Chris Torek, Jul 31, 2007
    #2
    1. Advertising

  3. Joakim Hove

    Joakim Hove Guest

    Dear Chris,

    thank you *very much* for a thorough and informative answer - I have
    learned a lot today.

    > The thing in front of the brace list *looks* exactly like a cast,
    > but is not actually a cast. Instead, it is the type-specifier
    > part of a "compound literal".


    The type-specifier of a compound literal - neat!

    > Because the call to func() is within a block (all function calls
    > in C are always inside a block -- you cannot call a function
    > outside the outermost block of some other function), the object
    > created by such a call has automatic duration. In practice, this
    > means you get runtime code to create the array. You may get
    > slightly better performance if you just give in and create an
    > actual object, which you can then make "static":


    I won't give in - I just love the compact calls like:

    func (3 , (const char *[]) {"S" , "S2" , "..."});

    which I can now use - thanks to your help. The call will be issued in
    the initialization part of the code, and performance is irrelevant.

    Regards

    Joakim Hove
    Joakim Hove, Jul 31, 2007
    #3
  4. Joakim Hove

    Martin Guest

    "Chris Torek" <> wrote in message
    news:...
    > If it were more complicated you might be out of luck, but because
    > C's string literals are kind of funny and sort-of-primitive, you
    > are in luck:
    >
    > void f(void) {
    > func(3, (const char *[]){"1", "2", "3"});
    > /* you can put in the array size too: (const char *[3]) */
    > }


    gcc version 3.0.4 emits the warning:

    ISO C89 forbids compound literals

    --
    Martin
    Martin, Aug 1, 2007
    #4
  5. Joakim Hove

    Chris Torek Guest

    >"Chris Torek" <> wrote in message
    >news:...
    >> If it were more complicated you might be out of luck, but because
    >> C's string literals are kind of funny and sort-of-primitive, you
    >> are in luck:
    >>
    >> void f(void) {
    >> func(3, (const char *[]){"1", "2", "3"});
    >> /* you can put in the array size too: (const char *[3]) */
    >> }


    In article <vd4si.61945$>,
    Martin <martin.o_brien@[no-spam]which.net> wrote:
    >gcc version 3.0.4 emits the warning:
    >
    > ISO C89 forbids compound literals


    Indeed. (The message might be slightly better-phrased if it said
    "ISO C90" or "ANSI C89", but the meaning is clear either way.)

    However, before the stuff I wrote above, I quoted the following
    sentence:

    >>>I am more than happy to accept C99 features.


    Compound literals are a C99 feature. That GCC warns about them in
    its default, neither-C89-nor-C99 not-quite-a-C-compiler compilation
    mode (and/or in its C89-specific mode), is probably a good thing.

    (I also described how to do the trick without using C99 features, or
    with different C99 features. If you use C99 features, you must of
    course have support for those in your compiler.)
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://web.torek.net/torek/index.html
    Reading email is like searching for food in the garbage, thanks to spammers.
    Chris Torek, Aug 1, 2007
    #5
  6. Joakim Hove

    Martin Guest


    > In article <vd4si.61945$>,
    > Martin <martin.o_brien@[no-spam]which.net> wrote:
    >>gcc version 3.0.4 emits the warning:
    >>
    >> ISO C89 forbids compound literals

    >
    > Indeed. (The message might be slightly better-phrased if it said
    > "ISO C90" or "ANSI C89", but the meaning is clear either way.)
    >
    > However, before the stuff I wrote above, I quoted the following
    > sentence:
    >
    > >>>I am more than happy to accept C99 features.


    Ah, right. I compile using

    gcc -Wall -pedantic -ansi

    so the warning is not surprising. And it is a warning: the code does compile
    and run. But I wouldn't let that success stop me disallowing such constructs
    being used at my workplace in a C89 compiler.

    --
    Martin
    Martin, Aug 1, 2007
    #6
    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. Andreas Lagemann
    Replies:
    8
    Views:
    464
    Mike Wahler
    Jan 10, 2005
  2. tiwy
    Replies:
    0
    Views:
    428
  3. Klaus Neuner
    Replies:
    7
    Views:
    474
    Klaus Neuner
    Jul 26, 2004
  4. Ben

    Strings, Strings and Damned Strings

    Ben, Jun 22, 2006, in forum: C Programming
    Replies:
    14
    Views:
    738
    Malcolm
    Jun 24, 2006
  5. Anonieko Ramos

    What's wrong with rpc-literal? Why use doc-literal?

    Anonieko Ramos, Sep 27, 2004, in forum: ASP .Net Web Services
    Replies:
    0
    Views:
    364
    Anonieko Ramos
    Sep 27, 2004
Loading...

Share This Page