For example:
#include <stdlib.h>
#define A 20
#define B 22
#define C (A+B)
int main()
{
srand(time(0));
int i = (rand()&1) + C;
return i;
}
In gdb,
(gdb) print C
No symbol "C" in current context.
How can I know what C is? Can gdb tell me? (I added rand() so we can't easily deduce what it was)
The preprocessor will have replaced C with (20+22). Is this value available in the debuginfo to print somehow?
In a real example where the macro could be exceedingly complex, I don't want to waste my time doing the job of the preprocessor.
How can I know what C is?
First of all you need to build the program with -g3 flag so that macro information is included in debugging information, start the program and show macro definition with info macro:
(gdb) start
Temporary breakpoint 1 at 0x40114e: file 1.c, line 9.
Starting program: /tmp/a.out
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.31-4.fc32.x86_64
Temporary breakpoint 1, main () at 1.c:9
9 srand(time(0));
(gdb) info macro C
Defined at /tmp/1.c:5
#define C (A+B)
(gdb) info macro A
Defined at /tmp/1.c:3
#define A 20
(gdb) info macro B
Defined at /tmp/1.c:4
#define B 22
You can also expand macro:
(gdb) macro expand C
expands to: (20+22)
Related
I have several configuration files each one containing the definition of some boolean macro, to be set to 0 or 1. Then, in my code, I check the value of such a macro to decide which part of the code to activate. Now comes the tricky part: I want to be sure that the header containing the definition of my macro has been included.
In the following example, if I forget to include the header file containing FOO definition, the compiler will print "world!", while I would like instead that it generated an error.
//in the configuration header file
#define FOO 1
//in a cpp file
#if FOO //I would like this to generate an error if I forgot to include the header file
#pragma message "Hello"
#else
#pragma message "world!"
#endif
Is it possible to achieve such a behaviour? How?
To clarify, I am not asking how to generate an error if a macro is not defined, but if it is possible to transform the #if FOO line so that, at the same time, it checks the boolean value and generates an error if FOO is not defined.
The point of having this would be that developers would know that their code should contain
SPECIAL_MACRO(FOO)
which, at the same time, check the boolean value of FOO as if it was an #if FOO statement, and prevents them from forgetting the inclusion of the header defining FOO.
Colleagues (hi Hartmut, Kurt) who maintained a large code base which was extensively configured with #defines ran exactly into the same problem. A simple mis-spelling, possibly in a make file, could result in subtle errors which were hard to track down. Their solution: Use function macros! In
#if SOME_COND()
// ...
#endif
the compiler complains if SOME_COND() is not defined, as opposed to a simple SOME_COND which will be replaced by 0 if undefined. I like it because it can be used to transport several values without cluttering the code up with additional #ifdefs.
The accepted answer of using function-macros is good, but if you want to keep normal macros - and still use the value of FOO if defined and generate an error otherwise you could do:
#if FOO / defined(FOO)
#else
#endif
If FOO is not defined it will trigger integer division by zero.
What about using the -Wundef gcc preprocessor option? This will only generate a warning, which can easily be turned to an error with -Werror=undef.
Macro CHECK(x) will:
fail if macro x is undefined,
evaluate to 00 if x is defined to 0
evaluate to 01 if x is defined to 1
$ cat main.cpp
#define CAT(x, y) x##y
#define CHECK(x) CAT(0, x)
// usage
#define COND0 0
#define COND1 1
#if CHECK(COND)
#endif
#if CHECK(COND0)
#pragma message "defined 1"
#else
#pragma message "defined 0"
#endif
#if CHECK(COND1)
#pragma message "defined 1"
#else
#pragma message "defined 0"
#endif
$ g++ main.cpp
main.cpp:9:1: error: user-defined literal in preprocessor expression
9 | #if CHECK(COND)
| ^~~~~
main.cpp:15:17: note: ‘#pragma message: defined 0’
15 | #pragma message "defined 0"
| ^~~~~~~~~~~
main.cpp:19:17: note: ‘#pragma message: defined 1’
19 | #pragma message "defined 1"
| ^~~~~~~~~~~
I think can solve your problem in simple tricky solution. I change your code as below and my code understand that header.h doesn't exist and show error to me.
#if FOO == 1
#pragma message "Hello"
#elif FOO == 2
#pragma message "world!"
#else
throw std::invalid_argument("Header didn't add to project");
#endif
only you need to change your initial value for Foo.
because compiler activate Foo==0 when it doesn't find FOO, you shouldn't use 0 value for your configuration. you should leave zero for header absence situation.instead you must use values greater than zero(1 , 2, 3 , ...).
Foo==0 absence situation.
Foo==1 Configuration 1.
Foo==2 Configuration 2.
.
.
.
Can somebody help me to understand the following statement? Why before #endif is "{" not "#ifdef", this seems illogical,
If you have a function implemented in C and want to call it from C++.
1.1). if you can modify C header files
Typically the declarations in a C header file are surrounded with
#ifdef __cplusplus
extern "C" {
#endif
[... C declarations ...]
#ifdef __cplusplus
}
#endif
to make it usable from C++.
If __cplusplus has been defined, and therefore it is C++ code, then we want
extern "C" {
and close it with
}
at the end.
I hope I have decoded your message properly.
I am still not sure which part yo have trouble with, so I'll explain both.
extern "C" tells the compiler that the functions are C functions. The difference is mainly the way functions are named/identified internally in the two languages; C++ has the parameter types "mangled" into the function name which is used internally to look up the correct function (remember, overloaded functions are to the linker -- which is potentially C++ agnostic -- normal, differently named functions). The #ifdef/#endif pairs just skip the extern "C" (and closing curly brace) if the compiler is a C compiler. That's necessary because extern "C" is not part of the C language, somewhat paradoxically, and the compiler would emit an error.
I found an explanation of g++ and VC's name mangling in this paper (which is 8 years old, so details may have changed, but the general concept is well layed out).
I did a quick test with a cygwin gcc/g++. Consider the following file overloaded-funcs.c:
int f(float x){}
#ifdef __cplusplus
/////////////////////////////////////////////////
// these f overloads are visible only to C++ compilers.
// A C compiler would not accept two functions with the same
// name.
int f(int x){}
int f(void){}
void g(void){}
/////////////////////////////////////////////////
#endif
#ifdef __cplusplus
/////////////////////////////////////////////////
// this part is visible only to C++ compilers
extern "C" int h(float){}
/////////////////////////////////////////////////
#endif
#ifdef __cplusplus
///////////////////////////////////////////////////
// This part, including an opening brace,
// is only visible to C++ compilers
extern "C"
{ // everything in this block are treated as
// C declarations/definitions.
/////////////////////////////////////////////////
#endif
/////////////////////////////////////////////////
// this part is visible to both C and C++ compilers
int i(void){}
/////////////////////////////////////////////////
#ifdef __cplusplus
/////////////////////////////////////////////////
// This brace is again only visible to C++ compilers
// (which have seen the opening brace above as well).
// C compilers would be confused by a closing brace out of nowhere
// because they did not see the opening brace.
} // closes the extern "C" block
/////////////////////////////////////////////////
#endif
First I looked at the preprocessor output with gcc's -E option in order to understand what the actual compiler sees.
$ gcc -E overloaded-funcs.c
# 1 "overloaded-funcs.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "overloaded-funcs.c"
int f(float x){}
# 40 "overloaded-funcs.c"
int i(void){}
Lines starting with # are ignored as far as the language goes. The lines representing real "code" are nicely syntax-highlighted. We can see that the preprocessor eliminates everything between the #ifdef __cpluspluss and corresponding #endifs from the input to the actual compiler.
Then I actually compiled the source file and inspected the resulting object file with the gnu program "nm" (which, according to its man page, "lists symbols from object files").
$ gcc -c -o ccompiled.o overloaded-funcs.c && nm --defined-only ccompiled.o
0000000000000000 b .bss
0000000000000000 d .data
0000000000000000 p .pdata
0000000000000000 r .rdata$zzz
0000000000000000 t .text
0000000000000000 r .xdata
0000000000000000 T f
000000000000000b T i
The right column lists the names which this object file contains. We are interested in the functions which are defined in it. The first column is the function address (offset), the letter in the second column indicates the "segment" where the symbol is found. Function definitions are in the "text" section. We clearly see the function names f and i. This is the name by which the linker or loader would find them.
Now I use a C++ compiler for preprocessing. The compiler defines the reserved word __cplusplus which makes the lines visible that were #defined out for a C compiler:
$ g++ -E overloaded-funcs.c
# 1 "overloaded-funcs.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "overloaded-funcs.c"
int f(float x){}
int f(int x){}
int f(void){}
void g(void){}
# 20 "overloaded-funcs.c"
extern "C" int h(float){}
# 30 "overloaded-funcs.c"
extern "C"
{
# 40 "overloaded-funcs.c"
int i(void){}
# 50 "overloaded-funcs.c"
}
Again the relevant lines of code are nicely highlighted.
Then I compiled it as C++ and examined the names in the object file
$ g++ -c -o cppcompiled.o overloaded-funcs.c && nm --defined-only cppcompiled.o
0000000000000000 b .bss
0000000000000000 d .data
0000000000000000 p .pdata
0000000000000000 r .rdata$zzz
0000000000000000 t .text
0000000000000000 r .xdata
0000000000000000 T _Z1ff
000000000000000b T _Z1fi
0000000000000014 T _Z1fv
000000000000001a T _Z1gv
0000000000000020 T h
000000000000002b T i
The function names just got a lot more complex -- "mangled". We still can see the "actual" names f and g in the middle of the name, prefixed with _Z1. Clearly, the parameter types are just encoded as single letters v, i and f for void, int and float behind the "actual" name part.
Note that the return value is not part of the generated function name, which means that it will normally not be known to the linker (which often has no other information than the object file). That is consistent with the language rule that the return value is not considered for overload resolution (and it is not possible to have two identically named functions which only differ in the return value). As far as the linker goes the overloaded versions of f are completely unrelated functions.
We can also see that the functions which were declared extern "C" have their old C name (h and i). C code in another translation unit could declare these functions and use them, and the linker would find that symbol (i or h), resolve the dependency and add the function's code to the executable. Such C code could not, however, link to a function f because as far as the linker can see no such function exists in our object file.
It is also clear that C++ is more type safe. If a C function is declared with the wrong parameter types the linker links happily against an implementation which expects totally different parameters. It cannot know what the function expects. In C++ the linker would simply not find an implementation with different parameters because their types are encoded in the mangled name.
extern simply tells us that the variable is defined elsewhere and not within the same block where it is used.
Basically, the value is assigned to it in a different block and this can be overwritten/changed in a different block as well.
So an extern variable is nothing but a global variable initialized with a legal value where it is declared in order to be used elsewhere. It can be accessed within any function/block. Also, a normal global variable can me made extern as well by placing the 'extern' keyword before its declaration/definition in any function/block.
This basically signifies that we are not initializing a new variable but instead we are using/accessing the global variable only. The main purpose of using extern variables is that they can be accessed between two different files which are part of a large program.
Here is a short program I wrote
#include <iostream>
#define test0 "abc"
#define test1 "def"
#define concat(x,y) x##y
int main()
{
for (int i = 0 ; i < 2 ; ++i)
std::cout << concat(test,i) << std::endl;
return 0;
}
But for some reason it doesn't compile (it concatenates i instead of i value), is there a way I can concatenate i's values instead of i's name?
test1.cpp: In function ‘int main()’:
test1.cpp:8:1: error: ‘testi’ was not declared in this scope
No. Macros are expanded before compilation (hence the term pre-processor), and can only manipulate the tokens that appear in the source code. The value of the variable isn't known until the program is run.
No.
The preprocessor (the part of the compiler that handles #define and #include) runs before any other compiler pass, and long before the program ever runs. The variable i will not have a value until the program runs.
Keep in mind that the preprocessor is little more than a text-replace tool for your program source code.
Put it simply, in my C++ knowledge (or lack of) FOO will be substituted with what is in parenthesis when this was defined. But what happens if the parenthesis are empty? Is it equivalent to 0? That means a #ifdef foo (0) will do the same thing as #ifdef foo ( )? If equivalent is any useful effect to be used with empty parentheses?
A macro expansion will just expand to whatever the macro is expanded to:
#include <stdio.h>
#define L (
#define R )
#define l {
#define r }
#define LR ()
int main LR
l
printf L "Hello, World\n" R;
return 0;
r
would compile perfectly fine (and if you hid the L/R/l/r macros in a header file, nobody would understand what you'd done. Note that spaces are needed at least in some places to ensure the macro actually expands.
This statement
#ifdef CRAPFOO ()
won't compile cleanly ("extra tokens at the end of #ifdef" in gcc, other compilers may give other errors.
#define CRAPFOO ()
#ifdef CRAPFOO
do something
#else
not something
#endif
will give do something as the result.
#define is an absolutely dumb textual replacement. So:
#define FOO ()
int main()
{
FOO;
}
becomes
int main()
{
();
}
You can test this with the -E option to g++ (and I think clang too), which means "just do preprocessing", or equivalently, just run the cpp tool, which is the c preprocessor.
i.e.
$ echo -e "#define FOO ()\nint main()\n{\n FOO;\n}" > def.cpp ; g++ -E def.cpp
# 1 "def.cpp"
# 1 "<command-line>"
# 1 "def.cpp"
int main()
{
();
}
(These are the Linux/other Unix command line tools).
#define is a preprocessor directive and is just a stupid text replacement rule which happens before actually compiling your code. There's no code model yet when applying the macro definitions.
#define FOO ()
replaces every occurrence of FOO with ().
#define FOO (0)
replaces every occurrence of FOO with (0).
#define FOO 0
replaces every occurrence of FOO with 0, which is not the same as (0) (there are cases in which this makes a difference).
However,
#define FOO()
replaces FOO() with nothing, doesn't touch FOO
I am trying a test build of some old code (hence the old compiler). I need to link C and F files, but I am getting the following error
error LNK2001: unresolved external symbol _flow
for each mention of a C file in the F code. Below is an example of how the f files link to the C files.
INTERFACE
SUBROUTINE flow (from, to, when, howmuch)
!MS$ATTRIBUTES C, ALIAS:'_flow' :: flow
REAL from
REAL to
REAL when
REAL howmuch
END SUBROUTINE flow
END INTERFACE
I am struggling to find any suggestions for the compiler I am using, but I suspect that the code is OK (I am assured the model has built from this code previously) and there is something wrong with what I am doing- I am wondering if I don't have the appropriate libraries to tell the compiler I am trying to link to C? I did attempt to download fortran.h and add this to my project file but this did not help, and when I added
include 'fortran.h'
to the relevant f files it caused syntax errors.
here is also the fortran.h file I am using
// Definitions for calling FORTRAN 77 from C++
typedef int INTEGER; // INTEGER 4 bytes
typedef float REAL; // REAL 4 bytes
typedef double DOUBLE_PRECISION; // DOUBLE PRECISION 8 bytes
typedef int LOGICAL; // LOGICAL 4 bytes
#include <f77char.h> // character n bytes
#include <f77cmplx.h> // complex
#include <f77matrx.h> // fmatrix class
// values for LOGICAL
#define FALSE 0
#define TRUE 1
// Macros for portable handling of linkage and calling conventions
//#ifdef F77_STUB_REQUIRED
// Typically, this branch is for Unix computers
// C++ stub functions:
#define SUBROUTINE inline void
#define INTEGER_FUNCTION inline INTEGER
#define REAL_FUNCTION inline REAL
#define LOGICAL_FUNCTION inline LOGICAL
#define DOUBLE_PRECISION_FUNCTION inline DOUBLE_PRECISION
// FORTRAN functions
#define SUBROUTINE_F77 extern "C" void
#define INTEGER_FUNCTION_F77 extern "C" int
#define REAL_FUNCTION_F77 extern "C" float
#define LOGICAL_FUNCTION_F77 extern "C" int
#define DOUBLE_PRECISION_FUNCTION_F77 extern "C" double
//#endif
// Array indexing differences between C++ and fortran
//#define B(i) b[i-1]
Thanks for reading- help greatly appreciated, and let me know if more information would be useful!