5

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.

7
  • 5
    No. Standard macro names must be identifiers, which means it must start with an alphabetic character or underscore, and continue with alphanumerics or underscores. All else apart, your comma macro would break function calls, initialization lists, and comma operators. In C, that's the end of it; in C++14 or later, you have punctuation options in numbers anyway. Commented Sep 29, 2016 at 16:18
  • 4
    10'000'000 in C++14. Won't happen, but wouldn't you want to #undef it afterwards? Or would you avoid writing , for the rest of the file when it should have its normal meaning? Commented Sep 29, 2016 at 16:18
  • 1
    Now, you can write literal number like 10'000'000. Commented Sep 29, 2016 at 16:18
  • 1
    BTW, with your define, you won't be able to call function with several arguments... Commented Sep 29, 2016 at 16:20
  • 2
    A common way to make numbers more readable in code is to multiply: #define MAX (10 * 1000 * 1000) Commented Sep 29, 2016 at 16:55

6 Answers 6

8

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__ 
Sign up to request clarification or add additional context in comments.

7 Comments

Finally a great macro metaprogramming. Thanks man, I was looking for this. I'm thinking about your solution to see if it can be simplified.
Your code was in need of extra macro expansions. I edited the code. Please check it. If corrected, I'll choose it as the answer. BTW, thanks =)
@AhmadSiavashi What compiler are you using? My code is conforming, C: ideone.com/N7us05, C++: ideone.com/BmCL2C
It's a matter of predecessor rules. Actually it should work for every standard compliant preprocessor. I didn't have GCC/Clang to test your solution, but as you have not used any preprocessor specific extensions it had to work on Microsoft's as well. But surprisingly it doesn't!. If the solution I sent works for you as well, it'd be better to select mine as it will also work for Microsoft. Do you agree?
This is a surprisingly clean solution to an unnecessarily dirty problem.
|
6

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.

Comments

5

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.

3 Comments

int a = 10,000,000; is a syntax error. The comma in a variable definition starts a new declarator, and 000 is not a valid declarator. In a = 10,000,000; the value 10 is assigned to a.
Oops. I've put parentheses in. It's contrived now, but the result still would be very funny. A nice one to impress the girls with.
Not necessarily thousands separator. It can be anywhere in the number.
3

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) 

2 Comments

There is something called variadic macro introduced in C99. I had your solution in mind but I'm trying to implement it using variadic macros. Have you heard about it?
2

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.

Comments

2

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.