Concatenate and stringize macro values for #include - c++

I'm trying to create a string from multiple macros/values for use in a #include. I'm doing this to clean up some code for an initial state in a simple state system.
I have 2 default, redefinable macros (if not defined there's a default value)
#define DEFAULT_STATE StateName // name of class
#define DEFAULT_STATE_LOCATION states/ // location of header file from root
The include directive is being used from a file 4 folders in from the root, so the include should look like this
#include "../../../../states/StateName.h"
based on the example above.
So I want to define a macro from the 4 values.
../../../../
DEFAULT_STATE_LOCATION
DEFAULT_STATE
.h
into some macro, say DEFAULT_STATE_INCLUDE
so I can say
#include #DEFAULT_STATE_INCLUDE
(to stringize the value for quotes)
That way I can change the default state and the path from the root of the header file for the default state in a prefix header, and the source using the #include will not have to be updated, and I can omit the constants from redefinition every time.
I'm not including the .h in the DEFAULT_STATE macro because I use the same macro to create and instance of the default state.
I've tried using the concatenation ##, and the stringize operator, and some tricks I've found online, but nothing worked.
I can define ../../../../ and .h in their own macros if needed.
But simply
#define DEFAULT_STATE_INCLUDE ../../../../ ## DEFAULT_STATE_LOCATION ## DEFAULT_STATE ## .h
#include #DEFAULT_STATE_INCLUDE
gives tons of errors.
Any help is appreciated.
Thanks

Note that footnote 143 in section §6.10.2 "Source file inclusion" of the C99 standard says:
143) Note that adjacent string literals are not concatenated into a single string literal (see the translation
phases in 5.1.1.2); thus, an expansion that results in two string literals is an invalid directive.
Thus, any string concatenation must be done outside the source code. Token concatenation with ## is not an option; that is used to build identifiers, and the bits of the header name you are joining are not identifiers.
I think you should simply use something like:
#ifndef STATE_HEADER
#define STATE_HEADER "states/StateName.h"
#endif
#include STATE_HEADER
and leave it to the build system, not the source code, to determine that -I../../../.. is required as an option to the compiler.

You'd better pass the include directory to gcc with -I option
-I../../../..
From gcc man page:
-I dir
Add the directory dir to the list of directories to be searched for header files.

This seems relevant: Computed Includes
My reading of that is that the #define macro has to include the " (quote) characters and that you can't rely on the stringize or concatenation operators to do it for you.

Related

Why isn't this valid syntax?

#include ("/" "include/foo.h")
#include ("/" "include/bar.h")
I.e., I have gotten things like..
char* a = "/" "include/foo.h";
to work. So I'm wondering, why not add this as a feature for the preprocessor to?
Or maybe.. are there any preprocessors that support this syntax?
My thinking is that you could do something like..
// config.h
#define LIB1_PATH "/include"
and then..
// main.c
#include "config.h"
#include (LIB1_PATH "foo.h")
#include (LIB1_PATH "bar.h")
If you then were to move "lib1" elsewhere in your project, you would only need to adjust config.h.
Why isn't this valid syntax?
Because the syntax for #include preprocessing directive is cpp.include for example:
# include " q-char-sequence " new-line
The ( ) characters are not allowed there. Multiple " are also not allowed, and q-char is any member of the source character set **except** new-line and ".
why not add this as a feature for the preprocessor to?
Because it would require work. To implement it.
are there any preprocessors that support this syntax?
I very much doubt. No.
My thinking is that you could do something like..
And for limited cases you kind-of can, the form of preprocessing directive takes:
# include pp-tokens new-line
For the usages, see this question. However not everything is possible, see this answer.
If you then were to move "lib1" elsewhere in your project, you would only need to adjust config.h.
No, the typical solution is to add include paths to your compiler. Then if you were to move lib1, you would change your build and compiler options, without any modification to the source code.
Keep your #include very simple - they are a very crude way to raw include other files. There is no reason to generate #include paths.
Concatenation is defined for string literals, as you've illustrated. From cppreference on string literals :
String literals placed side-by-side are concatenated at translation phase 6 (after the preprocessor). That is, "Hello," " world!" yields the (single) string "Hello, world!"
But the "string" in an #include directive is not a technically a string literal. Looking at how #include is defined on cppreference : #include "filename" we can see that the filename is some token delimited by " characters. This looks a lot like a string literal, but this is a coincidence. A string literal defines an object. It has an address and a size and every other property an object can have. An #include does not define an object, it is a preprocessor directive.

how to concatenate strings in #include statement [duplicate]

I would like to have include file paths dynamically created by a macro for a target-configuration-dependent part of my program.
for example, I would like to construct a macro that would be invoked like this:
#include TARGET_PATH_OF(header.h)
Which will expand to a something like this:
#include "corefoundation/header.h"
when the source is configured (in this case) for OSX
So far all attempts have failed. I'm hoping someone out there has done this before?
example of what does not work:
#include <iostream>
#include <boost/preprocessor.hpp>
#define Dir directory/
#define File filename.h
#define MakePath(f) BOOST_PP_STRINGIZE(BOOST_PP_CAT(Dir,f))
#define MyPath MakePath(File)
using namespace std;
int main() {
// this is a test - yes I know I could just concatenate strings here
// but that is not the case for #include
cout << MyPath << endl;
}
errors:
./enableif.cpp:31:13: error: pasting formed '/filename', an invalid preprocessing token
cout << MyPath << endl;
^
./enableif.cpp:26:16: note: expanded from macro 'MyPath'
#define MyPath MakePath(File)
^
./enableif.cpp:25:40: note: expanded from macro 'MakePath'
#define MakePath(f) BOOST_PP_STRINGIZE(BOOST_PP_CAT(Dir,f))
^
/usr/local/include/boost/preprocessor/cat.hpp:22:32: note: expanded from macro 'BOOST_PP_CAT'
# define BOOST_PP_CAT(a, b) BOOST_PP_CAT_I(a, b)
^
/usr/local/include/boost/preprocessor/cat.hpp:29:36: note: expanded from macro 'BOOST_PP_CAT_I'
# define BOOST_PP_CAT_I(a, b) a ## b
^
1 error generated.
I tend to agree with the comment in utnapistim's answer that you shouldn't do this even though you can. But, in fact, you can, with standard-conformant C compilers. [Note 1]
There are two issues to overcome. The first one is that you cannot use the ## operator to create something which is not a valid preprocessor token, and pathnames do not qualify as valid preprocessor tokens because they include / and . characters. (The . would be ok if the token started with a digit, but the / will never work.)
You don't actually need to concatenate tokens in order to stringify them with the # operator, since that operator will stringify an entire macro argument, and the argument may consist of multiple tokens. However, stringify respects whitespace [Note 2], so STRINGIFY(Dir File) won't work; it will result in "directory/ filename.h" and the extraneous space in the filename will cause the #include to fail. So you need to concate Dir and File without any whitespace.
The following solves the second problem by using a function-like macro which just returns its argument:
#define IDENT(x) x
#define XSTR(x) #x
#define STR(x) XSTR(x)
#define PATH(x,y) STR(IDENT(x)IDENT(y))
#define Dir sys/
#define File socket.h
#include PATH(Dir,File)
Warning: (Thanks to #jed for passing on this issue.) If the strings being concatenated contain identifiers which are defined elsewhere as macros, then unexpected macro substitution will occur here. Caution should be taken to avoid this scenario, particularly if Dir and/or File are not controlled (for example, by being defined as a command-line parameter in the compiler invocation).
You need to also be aware than some implementations may define words which are likely to show up in a token-like fashion in a file path. For example, GCC may define macros with names like unix and linux unless it is invoked with an explicit C standard (which is not the default). That could be triggered by paths like platform/linux/my-header.h or even linux-specific/my-header.h.
To avoid these issues, I'd recommend that if you use this hack:
you use a C (or C11) standards-conformant compiler setting, and
you place the sequence very early in your source file, ideally before including any other header, or at least any header outside of the standard library.
Also, you wouldn't need the complication of the IDENT macro if you could write the concatenation without spaces. For example:
#define XSTR(x) #x
#define STR(x) XSTR(x)
#define Dir sys
#define File socket.h
#include STR(Dir/File)
Notes
I tried it with clang, gcc and icc, as available on godbolt. I don't know if it works with Visual Studio.
More accurately, it semi-respects whitespace: whitespace is converted to a single space character.
I would like to have include file paths dynamically created by a macro for a target-configuration-dependent part of my program.
You should be unable to (and if you are able to do so, you probably shouldn't do this).
You are effectively trying to do the compiler's job in a source file, which does not make much sense. If you want to change include paths based on the machine you compile on, this is a solved problem (but not solved in a header file).
Canonical solution:
Use an IF in your Makefile or CMakeLists.txt, use custom property pages depending on the build configuration in Visual Studio (or simply set the particular settings for your build in the OS environment for your user).
Then, write the include directive as:
#include <filename.h> // no path here
and rely on the environment/build system to make the path available when the compiler is invoked.
This works for VS2013. (It can be done easier, ofcourse.)
#define myIDENT(x) x
#define myXSTR(x) #x
#define mySTR(x) myXSTR(x)
#define myPATH(x,y) mySTR(myIDENT(x)myIDENT(y))
#define myLIBAEdir D:\\Georgy\\myprojects\\LibraryAE\\build\\native\\include\\ //here whitespace!
#define myFile libae.h
#include myPATH(myLIBAEdir,myFile)
From your description, it sound like you discovered that not every "" is a string. In particular, #include "corefoundation/header.h" looks like an ordinary string but it isn't. Grammatically, quoted text outside preprocessor directives are intended for the compiler, and compile to null terminated string literals. Quoted text in preprocessor directives is interpreted by the preprocessor in an implementation-defined way.
That said, the error in your example is because Boost pasted the second and third token : / and filename. The first, fourth and fifth token (directory, . and h) are left unchanged. This is not what you wanted, obviously.
It's a lot easier to rely on automatic string concatenation. "directory/" "filename" is the same string literal as "directory/filename" Note that there is no + between the two fragments.

How to use a header file without a cpp file

I am a java developer, but I have had to learn C++ recently and I am confused about some things. What I would like to do is create a 'global' header file, which has a list of #define variables which will be constant throughout the suite I am creating. I created the header file, and I added some variables
#ifndef CONSTANTS_H
#define CONSTANTS_H
#define SM_START 1001;
#define SM_PAUSE 1002;
#define SM_STOP 1003;
#define SM_SAVE 1004;
#define SM_DISCARD 1005;
#define SM_SETUP 1007;
#endif // CONSTANTS_H
My problem is that I can't access these...
I have included the header file where I need it, but there is no way for me to access the constants inside of it. Do I Have to have a .cpp file? is there a way for me to access the constant variables?
First: You shouldn't put the semicolons at the end of the #define. #define is a preprocessor directive, meaning that it basically does text replacement of the defined name with the content. So if you do something like int a = SM_STOP + 1; it would be preprocessed to int a = 1003; + 1; with your code, which is not what you want.
Second: Headers are generally not compiled themselves but only for inclusion into *.cpp files or other headers (where #include is once again a text substitution). Therefore, yes you need to have a .cpp file somewhere (well not exactly, first of all you can choose a different extension and second you could even give the compiler a header as compile unit, but I would advise against it, at least until you know what you are doing). However you do not need to have a .cpp file for your constants, just #include your header into whatever file you want to use the constants in.
Third: Why are you using preprocessor defines here? This seems to be like a perfect job for an enum. Then you could put it into a namespace/struct for removing the need to prefix them (with SM_). Or you could just use C++11's new enum class, which behaves much like java's enums. I would avoid preprocessors wherever possible. Since it is simply text replacement and it doesn't respect any scoping and such, which makes it easy to get into problems (like with your semicolons).
The problem is that yuu have semicolons after #define. This is the only thing preventing you from using your "constants", which are not technically constants; they are preprocessor definitions.
Logically, the C++ compiler runs the text of your program through a preprocessor, a text filter that executes the directives starting in #. The #define directive instructs preprocessor to find all occurrences of its left part, and replace them verbatim with its right part. In your case, it includes semicolons, resulting in invalid expressions after replacement.
For example,
if (command == SM_DISCARD) ...
becomes
if (command == 1005;) ...
This is an error, and the compiler reports it as invalid syntax.
Use #include <constants.h> or whatever your filename is to include this file. Also, you don't need the semi-colons. #defines are text replacements done on the code by the compiler.
You don't need a cpp file. Including the header is enough.
The preprocessor expands your defines with whatever is after it.
SM_START will become 1001;
So an expression like:
int x = SM_START;
will translate to
int x = 1001;;
which is still legal.
But that semicolon could lead to trouble in something like:
int x = SM_START * 10;
which will be expanded to:
int x = 1001; * 10;
which is obviously illegal.
Also, preprocessor directives are not to be confused with globals. Even though you probably shouldn't be using globals, using #defines is probably worse than defining a class Global or just using variables grouped in a namespace.

C++ - #include "filename"

At this tutorial it mentions the following about #include "filename":
#include "filename" tells the compiler to look for the file in
directory containing the source file
doing the #include. If that fails,
it will act identically to the angled
brackets case.
What is meant by the bolded font sentence?
Thanks.
The bold bit simply means that, if the file specified inside quotes cannot be located using the " method, it will revert to the <> method.
I should mention that the bit about where it looks for the include files is actually incorrect. In both cases (quotes and angle brackets), the search locations are implementation defined.
From the lex.header section:
The sequences in both forms of header-names are mapped in an implementation-defined manner to headers or to external source file names as specified in 16.2.
The 16.2 section follows:
A #include directive shall identify a header or source file that can be processed by the implementation.
A preprocessing directive of the form
# include < h-char-sequence> new-line
searches a sequence of implementation-defined places for a header identified uniquely by the specified sequence between the < and > delimiters, and causes the replacement of that directive by the entire contents of the header. How the places are specified or the header identified is implementation-defined.
A preprocessing directive of the form
# include " q-char-sequence" new-line
causes the replacement of that directive by the entire contents of the source file identified by the specified sequence between the " delimiters. The named source file is searched for in an implementation-defined manner. If this search is not supported, or if the search fails, the directive is reprocessed as if it read
# include < h-char-sequence> new-line
with the identical contained sequence (including > characters, if any) from the original directive.
So the statement "... tells the compiler to look for the file in directory containing the source file doing the #include ..." is wrong. It's totally up to the implementation how it finds the files, in both cases.
Having said that, the rest is correct. If the method used by the " type does not locate the header, the method used by the <> type is then used. That's really all the bold bit means.
You just have to read the documentation for your particular implementation to see what those methods are.
While the exact details are implementation-dependent, there are a few common practices. In most common compilers, using the quotes #include "filename.h" searches the current directory by default. Using angle brackets #include <filename.h> searches system-defined library directories. What it is saying is that if the current directory doesn't have the file you need, it will search the system directories instead.
Note that some compilers may be different, and your compiler itself may have options to change these directories. There is also the possibility that system headers don't actually exist, but that #include <foo.h> is directly recognized by the compiler to enable certain built-in definitions.

Escaping a # symbol in a #define macro?

Without going into the gory details I want to use a #define macro that will expand to a #include but the '#' sign is confusing the preprocessor (as it thinks I want to quote an argument.)
For example, I want to do something like this:
#define MACRO(name) #include "name##foo"
And use it thus:
MACRO(Test)
Which will expand to:
#include "Testfoo"
The humble # sign is causing the preprocessor to barf. MinGW gives me the following error:
'#' is not followed by a macro parameter
I guess I need to escape the # sign but I don't if this is even possible.
Yes, macros are indeed evil...
It is possible to insert a hash token into the preprocessed token stream. You can do it as follows:
#define MACRO(hash, name) hash include name
MACRO(#,"hello")
—expands to:
# include "hello"
However, the standard explicitly rules out any further analysis of such line for the existence of preprocessing directives [cpp.rescan]:
The resulting completely macro-replaced preprocessing token sequence is not processed as a preprocessing directive even if it resembles one.
As far as I remember you cannot use another preprocessor directive in define.
The problem isn't actually getting a # symbol in the output of your preprocessor.
Apparently you want the preprocessor to reparse your file, to deal with newly created #include directives as part of macro expansion. It doesn't work that way. If a line starts with #, it's an instruction for the preprocessor and interpreted. If a line doesn't start with #, it's only subject to preprocessor transformation including macro substitution. This is a once-per-line test.
MACRO(Test)
does not start with #. Therefore it is not interpreted as a preprocessor directive; instead it's subject to macro replacement rules.
This is because the # has special meaning when used in a macro.
# means quote the following token (which should be a macro parameter name)
## means concatenate the preceding and following tokens.
In your situation the # is not followed by a proper token.
So in your situation we need to go through a level of indirection:
#define QUOTE(name) #name
#define TEST(name) QUOTE(name ## foo)
#include TEST(scot)
You can't do that. Preprocessor directives are recognized before macro expansion; if the macro expands into something that looks like a preprocessor directive, that directive will not be recognized. The best you can do is create a macro for the file name:
#define MACRO(name) "name##foo"
...
#include MACRO(Test)
This might work (it works for regular #define macros with no parameters, but I haven't tested it with macros with parameters).
#define MACRO(name) <name##foo>
#include MACRO(Test)
#define HASH_SIGN #
BOOST_PP_CAT(HASH_SIGN, include)
#define PARAM_NAME Param
#define GETNAME_(a) #a
#define GETNAME(a) GETNAME_(a)
int Param;
printf("%s = %i\n", GETNAME(PARAM_NAME), PARAM_NAME);