Using comma as macro name in C or C++

2020-07-16 12:52发布

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.

6条回答
何必那么认真
2楼-- · 2020-07-16 13:01

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).

查看更多
做个烂人
3楼-- · 2020-07-16 13:02

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.

查看更多
聊天终结者
4楼-- · 2020-07-16 13:08

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.

查看更多
啃猪蹄的小仙女
5楼-- · 2020-07-16 13:09

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)
查看更多
Rolldiameter
6楼-- · 2020-07-16 13:12

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.

查看更多
smile是对你的礼貌
7楼-- · 2020-07-16 13:17

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__
查看更多
登录 后发表回答