I have a problem with macros. I am supposed to come up with a macro ENTRY, that puts a value into an array ( scanf("%d",&ENTRY(x,i)) was given).
I tried: #define ENTRY (a,b) (a[b-1]), but that didn't work.
It created a compiler error that says, that a and b are undeclared.
But I thought that I don't have to declare variables used in macros, especially because, for example: #define min(a,b) ((a)<(b)?(a):(b)) worked in another program.
So what am I doing wrong here?
#include <stdio.h>
#define N 3
#define ENTRY (a,b) (a[b-1])
int main(void)
{
int x[N],i;
float y[N];
for(i=1;i<=N;i++){ printf("x_%d = ",i);scanf("%d",&ENTRY(x,i));}
for(i=1;i<=N;i++){ printf("y_%d = ",i);scanf("%lf",&ENTRY(y,i));}
return 0
}
Function-like macro definitions can't have whitespace after the macro name
#define ENTRY (a,b) (a[b-1]) // wrong
=>
#define ENTRY(a,b) ((a)[(b)-1]) // correct
6.10 – Preprocessing directives:
...
control-line:
...
# define identifier lparen identifier-listopt ) replacement-list new-line
# define identifier lparen ... ) replacement-list new-line
# define identifier lparen identifier-list , ... ) replacement-list new-line
...
lparen:
a ( character not immediately preceded by white-space
With the space, you get an object-like macro that expands to (a,b) (a[b-1]).
(For additional robustness, it's also recommended to parenthesize the parameters so that it also works if you pass in more complex expressions.)
Related
Considering the following snippet:
#include <stdio.h>
#define MY_MACRO(\
arg) \
arg
#define MY_MACRO2(t1, t2) t1##t2
#define MY_ a
#define MACRO b
int main() {
printf("%d\n", MY_MACRO2(MY_,MACRO)(45));
return 0;
}
It turns out to compile and display 45, however, if MY_ and MACRO were expanded before substitution, this code should not compile.
The reason why I notice this is when I read in the C standard the following:
6.10.3.1 (but also in C++ standard)
After the arguments for the invocation of a function-like macro have been identified,argument substitution takes place.A parameter in the replacement list, unless preceded by a # or ## preprocessing token or followed by a ## preprocessing token (see below), is replaced by the corresponding argument after all macros contained therein have been expanded. Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens are available
So if all macros contained in the arguments were expanded before replacement, why don't we end up with ab(45)?
To let constructions like X(X()) work. Note that while X() is expanded the X macro is disabled to avoid infinite recursions. Expanding arguments before expanding the macro let's one use X in the arguments.
A practical application of X(X()):
#define TEN(x) x x x x x x x x x x
#define HUNDRED(x) TEN(TEN(x))
I read about macros using Cppreference.
__LINE__ : expands to the source file line number, an integer constant, can be changed by the #line directive
I made c++ program to test __LINE__ macro.
#include <iostream>
using namespace std;
#line 10
#define L __LINE__
int main()
{
#line 20
int i = L;
cout<<i<<endl;
return 0;
}
Output :
20
Why output of the above code is 20? Why does not 10?
If you want to print 10 then change L into something that is not a macro:
constexpr int L = __LINE__;
Otherwise the macro L would be substituted on the line int i = L; and become:
int i = __LINE__;
Where it will have to be substituted again for the line number, and read the last #line directive.
Recall that macros perform token substitution. When you #define L __LINE__ it only specifies what tokens should L be substituted for when it appears in the source. It does not substitute anything at the point of L's own definition.
C++ - [cpp.replace]/9 or C - [6.10.3 Macro replacement]/9
A preprocessing directive of the form
# define identifier replacement-list new-line
defines an object-like macro that causes each subsequent instance of
the macro name to be replaced by the replacement list of preprocessing
tokens that constitute the remainder of the directive. The replacement
list is then rescanned for more macro names as specified below.
#define y 42
#define x y
This makes x defined as a sequence of preprocessing tokens that contains one token y. Not the token 42.
cout << x;
This will expad x to y and then y to 42.
#undef y
#define y "oops"
x is still defined as y.
cout << x;
You guess what happens. __LINE__ isn't special in this regard.
Your #line preprocessor directive changes the value to 20:
#line 20
The macro is expanded where used (not where defined) which is in your main() function, after the preprocessor directive which changes the value to 20.
I was wondering if there's a way to combine #define and #ifndef macro..
What this means is that I want to use #ifndef macro within the #define macro..
Since it's kind of hard to explain,, this is an example of what I want to do:
#define RUN_IF_DEBUG \
#ifndef DEBUG_MODE \
; // do nothing \
#else \
cout << "Run!" << endl; \
#endif
int main() {
RUN_IF_DEBUG
}
So I want the RUN_IF_DEBUG macro to run ONLY IF the DEBUG_MODE is defined...
Is there a way to do this?
It is usually done the other way around:
#ifndef DEBUG_MODE
# define RUN_IF_DEBUG ;
#else
# define RUN_IF_DEBUG cout << "Run!" << endl;
#endif
Simply do
#ifndef DEBUG_MODE
#define RUN_IF_DEBUG ; // do nothing
#else
#define RUN_IF_DEBUG cout << "Run!" << endl;
#endif
You can't put other preprocessor statements within a macro's body.
As from the c++ standards definitionsdraft section
16 Preprocessing directives
...
control-line:
...
# define identifier replacement-list new-line
# define identifier lparen identifier-listopt) replacement-list new-line
# define identifier lparen ... ) replacement-list new-line
# define identifier lparen identifier-list, ... ) replacement-list new-line
These are the allowed syntax variants for#define statements.
`
The problem is the line-continuation in the macro. What they do is put everything on a single line, so the expanded macro will look something like
int main() {
#ifndef DEBUG_MODE ; #else cout ...; #endif
}
This will not work very well with the preprocessor or the compiler.
Instead you should switch the nesting, and use #ifndef first, and #define the macros in the inner level.
Suppose some tokens FOO, BAR, and DUD (and possibly more) are #defined or not. I would like to have a macro EXTEND(name) that generates a valid extended name, e.g.
#define FOO
#undef BAR
#define DUD
EXTEND(object)
expands to
object_foo_dud
Is it possible to write macro EXTEND with less than O(2n) lines if there are n macro tokens (like FOO, BAR, and DUD)? I think it should be possible with O(n) lines, but how?
I've tried this:
#ifdef FOO
# define ExtFOO(name) name ## _foo
#else
# define ExtFOO(name) name
#endif
#ifdef BAR
# define ExtBAR(name) ExtFOO(name) ## _bar
#else
# define ExtBAR(name) ExtFOO(name)
#endif
#ifdef DUD
# define ExtDUD(name) ExtBAR(name) ## _dud
#else
# define ExtDUD(name) ExtBAR(name)
#endif
#define EXTEND(name) ExtDUD(name)
but
test.cc:26:5: error: pasting formed ')_dud', an invalid preprocessing token
EXTEND(object)
^
The ## operator concatenates two preprocessing tokens and must yield a single valid token. For example, from section 6.10.3.3 of the C99 spec:
For both object-like and function-like macro invocations, before the replacement list is
reexamined for more macro names to replace, each instance of a ## preprocessing token
in the replacement list (not from an argument) is deleted and the preceding preprocessing
token is concatenated with the following preprocessing token. Placemarker preprocessing tokens are handled specially: concatenation of two placemarkers results in a single placemarker preprocessing token, and concatenation of a placemarker with a non-placemarker preprocessing token results in the non-placemarker preprocessing token. If the result is not a valid preprocessing token, the behavior is undefined. The resulting token is available for further macro replacement. The order of evaluation of ## operators is unspecified.
So the expansion ExtBAR(name) ## _dud is invalid since it would yield ExtBAR(object)_dud.
I'd go with the following approach:
#ifdef FOO
# define ValFOO _foo
#else
# define ValFOO
#endif
#ifdef BAR
# define ValBAR _bar
#else
# define ValBAR
#endif
#ifdef DUD
# define ValDUD _dud
#else
# define ValDUD
#endif
#define CONCAT(a, b, c, d) a ## b ## c ## d
#define XCONCAT(a, b, c, d) CONCAT(a, b, c, d)
#define EXTEND(name) XCONCAT(name, ValFOO, ValBAR, ValDUD)
The intermediate XCONCAT step is needed because macro arguments are not expanded if they're concatenated using ##.
Shouldn't this:
#define MOGSH_CONCAT (x,y) x##y
#define MOGSH_DOUBLE (a,b) MOGSH_CONCAT(a,b)
#define MOGSH_DEFINEPROC (p) MOGSH_DOUBLE(_gt,p) options_dialog::p;
MOGSH_DEFINEPROC(AssignMainForm);
happily expand to:
_gtAssignMainForm options_dialog::AssignMainForm;
Given that _gt is not defined, _gtAssignMainForm is:
typedef void (__stdcall *_gtAssignMainForm)();
and options_dialog is just a class where AssignMainForm is a static member.
Instead, in MSVC9, I get the error:
'a' : undeclared identifier
on the line containing
MOGSH_DEFINEPROC(AssignMainForm);
In the definition of a function-like macro there can be no whitespace between the macro name and the ( beginning the parameter list.
#define MOGSH_CONCAT(x,y) x##y
// ^ no whitespace allowed here
As you have it now (with whitespace), MOGSH_CONCAT is an object-like macro with a replacement list of (x,y) x##y, which is why you are getting such strange results.