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.

Ahmad Siavashi
  • 979
  • 1
  • 12
  • 29
  • 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. – Jonathan Leffler Sep 29 '16 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*? – LogicStuff Sep 29 '16 at 16:18
  • 1
    Now, you can write literal number like `10'000'000`. – Jarod42 Sep 29 '16 at 16:18
  • 1
    BTW, with your define, you won't be able to call function with several arguments... – Jarod42 Sep 29 '16 at 16:20
  • 1
    @LogicStuff Who needs commas after all? The comma operator makes code hard to maintain and functions with more than one parameter load the stack heavily... – tofro Sep 29 '16 at 16:46
  • 2
    A common way to make numbers more readable in code is to multiply: `#define MAX (10 * 1000 * 1000)` – ash Sep 29 '16 at 16:55
  • 1
    Consider, btw, what would happen to all the "real" use of that punctation in code if it were redefined - it would be a nightmare. For example, `fopen("a", "r")` would change to `fopen("a" "r")`, which is not at all what you want here, and may actually compile (depending on compiler versions and settings). – ash Sep 29 '16 at 16:57

6 Answers6

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__
2501
  • 25,460
  • 4
  • 47
  • 87
  • 1
    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. – Ahmad Siavashi Sep 29 '16 at 17:05
  • 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 =) – Ahmad Siavashi Sep 29 '16 at 18:11
  • @AhmadSiavashi What compiler are you using? My code is conforming, C: https://ideone.com/N7us05, C++: https://ideone.com/BmCL2C – 2501 Sep 29 '16 at 18:16
  • 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? – Ahmad Siavashi Sep 29 '16 at 18:22
  • @AhmadSiavashi Sure, I'l add an edit explaining this. Could you just name the compiler Visual Studio version? – 2501 Sep 29 '16 at 18:23
  • It's `MSVC14` (Microsoft Visual Studio 2015 Update 3). Thank you. – Ahmad Siavashi Sep 29 '16 at 18:28
  • 1
    This is a surprisingly clean solution to an unnecessarily dirty problem. – KevinZ Oct 03 '16 at 15:19
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.

Community
  • 1
  • 1
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
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
    `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`. – Jonathan Leffler Sep 29 '16 at 16:24
  • 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. –  Sep 29 '16 at 16:25
  • 1
    Not necessarily thousands separator. It can be anywhere in the number. – HolyBlackCat Sep 29 '16 at 16:25
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)
Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • 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? – Ahmad Siavashi Sep 29 '16 at 16:39
  • Look at this: http://stackoverflow.com/questions/10458402/concatenation-of-tokens-in-variadic-macros – Ahmad Siavashi Sep 29 '16 at 16:40
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.

2501
  • 25,460
  • 4
  • 47
  • 87
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).

Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137