Thread: Validating variadic arguments

  1. #1
    Registered User
    Join Date
    May 2016
    Posts
    104

    Validating variadic arguments

    Hello guys,

    what would be the best way to ensure that variadic arguments passed to my function are indeed the type they're supposed to be?

    I'm detecting the type internally, by parsing a string which is supposed to contain characters that identify the type of each argument, e.g 'i' or 'd' for integers, 'u' for unsigned ' f' for float, etc.

    However, I want to be able to detect if the user calls my function passing the wrong arguments for the given type specifiers.

    One would think that when assigning va_arg(va_list, type) to a variable of the wrong type, there would be an error, but if we are dealing with a simple integral conversion there would be no error then. Not to mention the fact that I would like to store the arguments in a void*, to make things neater and more concise. Then I'd use the type to decipher the void* when I'd need it.

    I thought about using sizeof but I quickly dismissed it as being unfeasible.
    I'm at a loss here so I welcome any ideas you might have.

    Thank you!

  2. #2
    Registered User
    Join Date
    Dec 2017
    Posts
    1,632
    There's no way to do it in general in the function itself. The only possibility is to write your own preprocessor that checks the function usage before compilation. gcc gives warnings if the argument types of printf don't match the format string, but it's only able to do that because it has knowledge of the printf standard library function.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  3. #3
    Registered User
    Join Date
    Dec 2017
    Posts
    1,632
    Playing with variadics a little, I discovered something interesting about how they are implemented in gcc.

    Although the following produces warnings about the formats not matching up, it prints the three ints first and then the three doubles. This is because the values are passed in registers and when you ask for an int you get the one in the first int register; when you ask for a double, you get the one in the first double register.

    Code:
    #include <stdio.h>
    int main() {
        printf("%d %d %d %.1f %.1f %.1f\n",
               1.1, 1, 2.2, 2, 3.3, 3);
        return 0;
    }
    
    /* Output:
    1 2 3 1.1 2.2 3.3
    */
    Even our own variadic functions work that way. If you ask for an int, you will get the first int that was passed in. You need to overload (in the sense of overburden) the registers to screw it up.

    Code:
    #include <stdio.h>
    int main() {
        printf("%d %d %d %.1f %.1f %.1f\n"
               "%d %d %d %.1f %.1f %.1f\n"
               "%d %d %d %.1f %.1f %.1f\n"
               "%d %d %d %.1f %.1f %.1f\n"
               "%d %d %d %.1f %.1f %.1f\n",
               1.1, 11, 2.1, 21, 3.1, 31,
               1.2, 12, 2.2, 22, 3.2, 32,
               1.3, 13, 2.3, 23, 3.3, 33,
               1.4, 14, 2.4, 24, 3.4, 34,
               1.5, 15, 2.5, 25, 3.5, 35);
        return 0;
    }
    
    /* Output:
    11 21 31 1.1 2.1 3.1
    12 22 32 1.2 2.2 3.2
    13 23 1717986918 1.3 2.3 0.0
    1717986918 14 858993459 0.0 3.4 0.0
    0 15 0 0.0 3.5 0.0
    */
    Last edited by john.c; 08-15-2018 at 12:01 AM.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    I'm detecting the type internally, by parsing a string which is supposed to contain characters that identify the type of each argument, e.g 'i' or 'd' for integers, 'u' for unsigned ' f' for float, etc.
    If GCC is your compiler of choice (or Clang), then make your format strings the same as printf.
    Using the GNU Compiler Collection (GCC): Common Function Attributes

    You get this for free at that point.
    Quote Originally Posted by GCC Manual
    format (archetype, string-index, first-to-check)

    The format attribute specifies that a function takes printf, scanf, strftime or strfmon style arguments that should be type-checked against a format string. For example, the declaration:

    extern int
    my_printf (void *my_object, const char *my_format, ...)
    __attribute__ ((format (printf, 2, 3)));

    causes the compiler to check the arguments in calls to my_printf for consistency with the printf style format string argument my_format.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    May 2016
    Posts
    104
    Gee Salem, man I could kiss you right now. Here, kisses!

    I'm not certain I'll be able to use it, as our school projects have to pass through a bot that checks the code meets certain style and syntax guidelines as well as other school rules.And sadly, the stupid bot doesn't recognize compiler attributes, so it thinks the project will not compile. Let's see how I manage to work around that.

    John, that is pretty interesting! it doesn't offer complete fool protection -like I ask for an int but there are no ints for instance- but it is certainly better than nothing. I will definitely be using this if can't circumvent the school bot.

    Thank you much guys!
    Kudos.

  6. #6
    Registered User
    Join Date
    Dec 2017
    Posts
    1,632
    Quote Originally Posted by Dren View Post
    John, that is pretty interesting! it doesn't offer complete fool protection -like I ask for an int but there are no ints for instance- but it is certainly better than nothing. I will definitely be using this if can't circumvent the school bot.
    I didn't mean it as a solution to your problem. It isn't. It's just interesting.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Quote Originally Posted by Dren View Post
    I'm not certain I'll be able to use it, as our school projects have to pass through a bot that checks the code meets certain style and syntax guidelines as well as other school rules.And sadly, the stupid bot doesn't recognize compiler attributes, so it thinks the project will not compile. Let's see how I manage to work around that.
    You can always do this, so you only get the format checking in an environment you control.
    Code:
    extern int
    my_printf (void *my_object, const char *my_format, ...)
    #ifdef COMPILE_LOCALLY_WITH_CHECKS
    __attribute__ ((format (printf, 2, 3)))
    #endif
    ;
    You will have fixed all the issues it would ever detect by the time you get to submission time.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    Registered User
    Join Date
    May 2016
    Posts
    104
    Once more Salem to the rescue They ought to change the name of these forums to "Ask Salem" lol.
    I don't even know how you knew the bot would ignore the preprocessor directives, but that works like a charm.

    Thank you thank you thank you!
    Last edited by Dren; 08-16-2018 at 09:56 PM. Reason: Ask annoying question. Moved it to another thread.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. how to write variadic template for variadic function?
    By Dave11 in forum C++ Programming
    Replies: 4
    Last Post: 04-02-2015, 03:16 AM
  2. variadic arguments and multiplying
    By Darkroman in forum C Programming
    Replies: 2
    Last Post: 08-23-2011, 11:02 PM
  3. Variadic function
    By Richardcavell in forum C Programming
    Replies: 17
    Last Post: 03-01-2011, 01:34 AM
  4. variadic templates
    By Elkvis in forum C++ Programming
    Replies: 2
    Last Post: 05-11-2009, 03:57 PM
  5. Variadic Functions
    By coder8137 in forum C Programming
    Replies: 9
    Last Post: 01-12-2007, 08:25 PM

Tags for this Thread