Additional arguments in a C function

In a C function, I want to check if an input argument is present ("value" in my case).

i.e:.

void Console(char string[], int32_t value)
{
    // write string here
    // write value here, if it exists
}

      

When using operator, if(value != NULL)

my console () function sends 4096

How can I check and act based on the existence of the argument?

+8


source to share


3 answers


Optional arguments are generally not allowed in C (but they exist in C ++ and Ocaml , etc.). The only exceptions are function variables (for example printf

).

Historically, the POSIX open (2) function took an optional third argument in some cases (at the time it was defined - in the 1970s and 1980s), calling conventions practically pushed arguments onto the call stack, so ignoring that argument was simple to implement). If you look today at the recent implementation of this open

function in free software libc implementations on Linux like musl-libc , you will see in its src / fcntl / open.c file that it uses variadic facilities (which are often implemented as embedded compilers). <stdarg.h>

By the way, you can define some macros to fill in "missing" arguments, so if you have

  void console(const char*, int32_t);

      

you might as well

  #define console_plain(Msg) console((Msg),0)

      

and that could be instead of some built-in function in some header like



  static void inline console_plain (const char*msg) 
  { console(msg, 0); }

      

then use console_plain("hello here")

elsewhere

Then your variable function should determine how and what arguments are allowed (after a non-empty sequence of fixed arguments). And use stdarg (3) to get those variable (actual) arguments.

The actual arguments are known mostly at compile time and not at run time. Thus, you need a convention that often determines which variable value argument is allowed from the required fixed arguments. In particular, you have no way to check for the existence of an argument (this information is lost at runtime).

By the way, with variable functions, you usually lose the type checking that most C compilers provide (at least when you include all warnings, for example gcc -Wall -Wextra

). When using GCC have you may have some function __attribute__

-s
(for example format

, sentinel

....) in the prior art to help it. You can even customize gcc

with the deprecated MELT or in 2019 with your GCC plugin to add your own attributes by doing your own type checking.

How can I check and act based on the existence of an argument?

With the current common calling conventions (for example, learning about x86-64 ABIs ) you usually cannot do this (without using variable number functions).

+9


source


If you want to differentiate between function calls that take one or two arguments, you can use macros.

While you can reproduce your desired behavior, there are some things to note:

  • Macro photography hides the overload for casual readers of your code who can't see what Console

    a macro is. C sees a lot of details, so if you have two different functions they should probably have different names, perhaps cons_str

    and cons_str_int

    .

  • The macro will generate a compiler error if you pass more than two arguments, or if the arguments are not compatible with the required C string and int types. This is actually good.

  • Real variadic functions, such as printf

    those that use an interface from <stdarg.h>

    , should be able to infer the types and number of variadic arguments. This printf

    is done using format specifiers %

    . A macro can switch between different implementations based only on the number of arguments.



Anyway, here's the implementation. Be careful.

#include <stdlib.h>
#include <stdio.h>

#define NARGS(...) NARGS_(__VA_ARGS__, 5, 4, 3, 2, 1, 0)
#define NARGS_(_5, _4, _3, _2, _1, N, ...) N

#define CONC(A, B) CONC_(A, B)
#define CONC_(A, B) A##B

#define Console(...) CONC(Console, NARGS(__VA_ARGS__))(__VA_ARGS__)



void Console1(const char string[])
{
    printf("%s\n", string);
}

void Console2(const char string[], int32_t value)
{
    printf("%s: %d\n", string, value);
}

int main()
{
    Console("Hello");
    Console("Today number is", 712);

    return 0;
}

      

+2


source


It sounds like you are trying to use hacking to potentially make it easier for yourself, or whoever opened your source, to be "on record." I say "in write mode" (not read / write) because this kind of code is very difficult to read, because of all the hidden code, because of the magic macros that you will need. C is not a smart language. Compilers may be smart, but the semantics of the language are pretty pedantic. You must strictly follow the rules, otherwise you risk making bad software, or worse, not working at all.


The "correct" way to do this, without creating an entirely new programming language, is to provide two arguments, and when the second should not be used, it must either be passed as NULL

if it is a pointer, or some exception to the number, such as -1

if it is a digital type.

Another approach is to create two separate functions with names console_full

such as: console

and console_full

. Accordingly, with one and two arguments.

But if you still don't have the stdarg.h

above approaches, you can turn it on stdarg.h

to do it for you.

void Console (char *string, ...) /* Note the ... */
{
    va_list param;
    int32_t optValue = (-1); /* -1 would indicate optValue is to be ignored */

    // write string here

    va_start(param, string);

    optValue = va_arg(param, int32_t);

    if(optValue != (-1))
    {
        /* Work with 'optValue' */
    }

    va_end(param);
}

      

Which way doesn't work because you don't know the types of additional arguments and you don't know how many there are. To know these things, you have to do the same as printf-like functions, parse specific tokens within the string that assume the argument exists and what type of argument it is, or at least just use a constant variable counter. You can macro further, that the argument counting happens automatically.

+2


source







All Articles