Reputation: 101
Im trying to learn some c++, and I bumped into this code:
static const unsigned char t_CountBits13[8192] = {
#define B2(n) n, n+1, n+1, n+2
#define B4(n) B2(n), B2(n+1), B2(n+1), B2(n+2)
#define B6(n) B4(n), B4(n+1), B4(n+1), B4(n+2)
#define B8(n) B6(n), B6(n+1), B6(n+1), B6(n+2)
#define B10(n) B8(n), B8(n+1), B8(n+1), B8(n+2)
#define B12(n) B10(n), B10(n+1), B10(n+1), B10(n+2)
B12(0), B12(1)
};
I think this is pretty weird !
Question 1: Is this the same as:
#define B2(n) n, n+1, n+1, n+2
#define B4(n) B2(n), B2(n+1), B2(n+1), B2(n+2)
#define B6(n) B4(n), B4(n+1), B4(n+1), B4(n+2)
#define B8(n) B6(n), B6(n+1), B6(n+1), B6(n+2)
#define B10(n) B8(n), B8(n+1), B8(n+1), B8(n+2)
#define B12(n) B10(n), B10(n+1), B10(n+1), B10(n+2)
static const unsigned char t_CountBits13[8192] = {B12(0), B12(1)};
Question 2:
#define B2(n) n, n+1, n+1, n+2
Am I right to think that a C++ function can only return one value ? Because it seems like you define a function here that returns multiple (like lua for example)
Kind regards!
Upvotes: 0
Views: 258
Reputation: 510
Answer 1: The array will be initialized with the same value. The preprocessed result will look a bit different with regards to white space, so textually it isn't the same, but the result of compilation should be identical.
Answer 2: As mentioned in the comments, these are not C++ functions, but are macros interpreted by the C pre-processor. These result in text expansion prior to the compiler interpreting it. The expansion in your example is too large to show here (2 * 4^6 = 8192 elements is a lot). I'll reduce it for an example.
Original source code:
static const unsigned char data[] = {
#define B2(n) n, n+1
#define B4(n) B2(n), B2(n+1)
B4(1), B4(2)
};
output of preprocessor (for example, as output by gcc -E tst.c
:
# 1 "tst.c"
# 1 "<command-line"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line" 2
# 1 "tst.c"
static const unsigned char data[] = {
1, 1 +1, 1 +1, 1 +1 +1, 2, 2 +1, 2 +1, 2 +1 +1
};
Note the blank lines where the preprocessing directives were. Also note that the values are not the result of the arithmetic, but the text expansion. This is the code the compiler will actually interpret. Also note that the expansions are recursive through the #define
macros defined above.
The lines starting with #
are additional information from the preprocessor and includes things like defines from the command line and file information. It's fairly bland in the example, but if you were to have a #include <somefile.h>
you'd see its contents, and the contents of the files it includes (recursively), as well as some #
lines indicating the real line numbers of those locations (often used by the compiler for displaying warning and error messages, since by the time it gets it the line that used to be your line 5 might now be line 2592, but you'd expect the warning to indicate line 5).
Looking at the output of the preprocessor can be quite helpful debugging weird errors. When the message from the compiler just doesn't make sense, it can be an errant #define replacing text you didn't expect. For example, you might have the following code
int limit(int x) {
if (x > LIMIT) {
return LIMIT;
}
return x;
}
The compiler might say error: expected identifier or '(' before numeric constant
on the line int limit(int x) {
If you look at the preprocessed output you might find
int 5(int x) {
and realize that the following line made it into your code (either original source file or from an included file)
#define limit 5
Note how limit
is lower case, and we tried naming a function that, but the preprocessor replaced it with the 5. The #define
should probably have been LIMIT
(all uppercase)
This has been a bit of a long answer, but I hope illustrates the text-replacement nature of #define
s and some hints at finding the intermediary representations of your own code.
Note: The actual output of your preprocessor depends on your toolchain. The information above holds for the GNU Compiler Collection. Some toolchains don't actually separate the pre-processor phase from the compilation phase, but simply behave as though they do, which is allowed by the language.
Upvotes: 2