TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

A Better Varargs

75 pointsby Anilm3over 9 years ago

7 comments

ryanprichardover 9 years ago
The example does not actually use compound literals. (i.e. _arg&#x27;s initializer would work in C89.) It does use two other C99 features, though -- variadic macros and a for-loop-scoped variable declaration. The biggest compatibility issue, though, are its use of GCC extensions:<p>- Statement expressions: e.g.: int x = ({ int y = 0; y; });<p>- If zero-args are allowed (e.g. bar()), then _args is 0-sized, which is also non-standard.<p>These GCC extensions are somewhat common. Clang has them, and (I think) EDG&#x27;s frontend does too. MSVC does not have either of them, even in MSVC 2015.<p>That said, a compound literal might be a good way to remove the extension use, but as long as bar() returns void, the do-while(0) trick is also sufficient for replacing the statement expression.<p>I think this compound literal usage works:<p><pre><code> #define bar(...) (bar( \ sizeof((const char*[]) { NULL, __VA_ARGS__ }) &#x2F; sizeof(const char*) - 1, \ (const char*[]) { NULL, __VA_ARGS__ } + 1)) </code></pre> bar() results in trailing commas. My impression is that C99 allows them in array initializers. (I saw an example in the n1256 C draft.) I don&#x27;t recall whether C89 also had them. __VA_ARGS__ is expanded twice, but I think that&#x27;s OK, because sizeof() only evaluates its operand when it has VLA type, and it never will. This code will work in MSVC 2013 (if not earlier).
评论 #11078288 未加载
评论 #11081863 未加载
评论 #11078184 未加载
pklauslerover 9 years ago
The presented example will work only if the actual arguments are all of the same type. For more general usage, namely printf() and its variants, the variadic macro fails.
AndyKelleyover 9 years ago
This works when the arguments are all the same type. But what if you wanted to implement, e.g. printf with this?
评论 #11078336 未加载
评论 #11077490 未加载
looneysquashover 9 years ago
For what it&#x27;s worth, C++ has a better way to do this.<p><a href="http:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;cpp&#x2F;language&#x2F;parameter_pack" rel="nofollow">http:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;cpp&#x2F;language&#x2F;parameter_pack</a><p>You might want to skip down to the example, a type safe printf.
评论 #11078890 未加载
hlandauover 9 years ago
I should note that if you just want to get the number of arguments for a call to a varargs function rather than trust people to terminate the arguments with NULL properly, you can do this with the C99 preprocessor:<p>#define foo(...) foo(PP_NUM_ARGS(__VA_ARGS__), __VA_ARGS__)<p>where PP_NUM_ARGS is a macro to determine the number of arguments; you can find such a macro easily by searching. Of course you could just do #define foo(...) foo(__VA_ARGS__, NULL), but this lets you include NULL values in the list.<p>Since the count takes up the first argument to the actual varargs function, you can call it with zero arguments. No type checking, though as mentioned above you might be able to do something interesting about that with _Generic.
评论 #11078767 未加载
shiroover 9 years ago
Using macro fails if I happen to pass a variable named _args as one of the arguments to bar(). Is there any clever trick to simulate gensym in C macro?
评论 #11078736 未加载
评论 #11077615 未加载
stonogoover 9 years ago
I strongly appreciate the irony of having &quot;acumen&quot; defined for me on the same page as this idea of &quot;better&quot;.