Using comma as macro name in C or C++

会有一股神秘感。 提交于 2020-02-02 03:02:09

问题


I'd like to do something like:

#define , 
#define MAX 10,000,000
// ...
#undef ,

is there any trick to do so?

EDIT: I know about the ' digit separator in C++14. I'm looking for a trick to do the same for uncompliant compilers.
EDIT2: Please consider Variadic Macros.


回答1:


Warning, black magic ahead.

Macros can indeed be used, albeit with a preset number of arguments. This number can be arbitrary, but each must be written by hand:

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

#define MERGE_EXPAND( a , b )     a##b
#define MERGE( a , b )            MERGE_EXPAND( a , b )

#define COUNT_PICK( a , b , c , pick , ... )  pick

#define COUNT( ... )    COUNT_PICK( __VA_ARGS__ , 3 , 2 , 1 , 0 )

#define JOIN_1( a )           a
#define JOIN_2( a , b )       a##b
#define JOIN_3( a , b , c )   a##b##c

#define JOIN( ... ) MERGE( JOIN_ , COUNT( __VA_ARGS__ ) )( __VA_ARGS__ )

int main( void )
{
    printf( "%d\n" , JOIN( 12345 ) ) ;
    printf( "%d\n" , JOIN( 100,44 ) ) ;
    printf( "%d\n" , JOIN( -10,44,9999 ) ) ;  

    return EXIT_SUCCESS ;
}

The macro COUNT count the number of arguments passed to it. This is done by passing arguments to the helper macro COUNT_PICK, and adding additional argument which are consecutive numbers in reverse order. The number of original arguments passed to COUNT then manipulates the arguments of COUNT_PICK, so that one of the numbers is chosen.

That chosen number is then merged wtih JOIN, resulting in either JOIN_1, JOIN_2, or JOIN_3. The chosen macro is then used with original arguments and simply merges them into a single integer literal.

This example can be expanded by manually defining more JOIN_X macros where X is a consecutive number. Simultaneously the macros COUNT and COUNT_PICK, must be altered as well.

As an additional benefit, passing invalid arguments, like:

JOIN( 10,+44 );
JOIN( 10,-44 );
JOIN( 10,*44 );
JOIN( 10,/44 );
JOIN( /10,44 );
//etc...

will yield a compile time warning, but still allows for arguments that will result in a valid integer constant.

To be used with a Microsoft compiler, tested with SVC14 (Microsoft Visual Studio 2015 Update 3), the code must be amended. Macros COUNT_PICK and MERGE must be wrapped with an additional expand macro:

#define EXPAND(...)   __VA_ARGS__



回答2:


is there any trick to do so?

No you can't. Macros have a specific set of characters that can be used to name them (see details here please). , isn't one of them.




回答3:


Go shopping for the latest C++14 compliant compiler. That allows you to use ' as a thousands separator:

#define MAX 10'000'000

although using a macro in such a brand spanking new C++ compiler is an anachronism.

Writing 10,000,000 would not end well. If used in an expression then , will stand in for the comma operator.

So int a = (10,000,000) would be zero. It could be worse than that: a leading zero denotes an octal literal, so int a = (10,000,010) would actually be 8.




回答4:


Sort of, although it's a bit tedious and inelegant:

#define constant(a) (a)
#define constant2(a,b) (a##b)
#define constant3(a,b,c) (a##b##c)

constant(10000)
constant2(10,000)
constant3(10,000,000)



回答5:


You can always use a custom function that will parse a string literal:

int value = Number( "100,000,000" );

The downsite is the some small overhead for parsing, and the benefits are error checking, and the ability to use any format you want.

The parsing itself can be minimized by reusing const varibles in outer most scopes.




回答6:


One trick to enhance code clarity is to define macro as:

#define MAX    (10 * 1000 * 1000)

The rationale is that modern compilers are smart enough to simplify the expression into single integer constant 10000000. This is known as constant propagation (or constant folding).



来源:https://stackoverflow.com/questions/39775329/using-comma-as-macro-name-in-c-or-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!