Question

sgrm123 on Tue, 10 Jul 2018 11:27:03


Hi,

In C++ is there a way to create char* array and int array with a pre-processor macro?

and How to initialize array in macro?

Replies

RLWA32 on Tue, 10 Jul 2018 11:43:51


Why would you want to use the preprocessor for these tasks?

sgrm123 on Tue, 10 Jul 2018 11:46:44


Why would you want to use the preprocessor for these tasks?
just to know about macro's I asked.

Darran Rowe on Tue, 10 Jul 2018 11:52:33


I'm not exactly sure what you are asking here, because a pre-processor macro doesn't "create" anything.

All a pre-processor macro does is replace the macro with the substitution text. Suppose you have the three macros:

#define MY_TEXT "Text"
#define MORE_TEXT(a) "Text: " #a //doesn't require a string parameter
#define YET_MORE_TEXT(a) "Text: " a //requires a string parameter

The compiler will literally just replace any macro names with the text given, any parameters will replace any named parameters too.

You can see what the compiler does if you tell it to output the pre-processed file. So if we use the following program:

#include <cstdio>

#define MY_TEXT "Text"
#define MORE_TEXT(a) "Text: " #a //doesn't require a string parameter
#define YET_MORE_TEXT(a) "Text: " a //requires a string parameter

int wmain()
{
	wprintf(L"%hs\n", MY_TEXT);
	wprintf(L"%hs\n", MORE_TEXT(hah));
	wprintf(L"%hs\n", YET_MORE_TEXT("hah"));
	return 0;
}

Tell the compiler to output the pre-processed file:

You will find that the compiler outputs a .i file in the same location that the .obj files are for that target:

Then look at the file listing, removing the headers:

int wmain()
{
	wprintf(L"%hs\n", "Text");
	wprintf(L"%hs\n", "Text: " "hah");
	wprintf(L"%hs\n", "Text: " "hah");
	return 0;
}

You should see that all the compiler did in this one step is replace the macro name with the body of the macro itself. For the parameters, for the first one, the # translated what was in the () into "", and for the second one it just directly replaced the parameters.

So all you can do with a macro is give a fancy name to a string literal, but you are able to do that with a global variable or constexpr function anyway. What's more, the type of a string literal is defined by the standard to be:

"String"; //const char[7]
L"String"; //const wchar_t[7]
u8"String"; //const char[7]
u"String"; //const char16_t[7]
U"String"; //const char32_t[7]

So technically, you can't even get the right type since any array to pointer degrading would go to const char_type *. (Visual C++ does allow it to go to char_type *, but the standard forbids this with good reason).

So no, if you want to get a general purpose char *, then you need a function, or if you are dead set on a macro, have the macro be the code to create the buffer and initialise it at runtime.


This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.


sgrm123 on Tue, 10 Jul 2018 11:57:42


I'm not exactly sure what you are asking here, because a pre-processor macro doesn't "create" anything.

All a pre-processor macro does is replace the macro with the substitution text. Suppose you have the three macros:

#define MY_TEXT "Text"
#define MORE_TEXT(a) "Text: " #a //doesn't require a string parameter
#define YET_MORE_TEXT(a) "Text: " a //requires a string parameter

The compiler will literally just replace any macro names with the text given, any parameters will replace any named parameters too.

You can see what the compiler does if you tell it to output the pre-processed file. So if we use the following program:

#include <cstdio>

#define MY_TEXT "Text"
#define MORE_TEXT(a) "Text: " #a //doesn't require a string parameter
#define YET_MORE_TEXT(a) "Text: " a //requires a string parameter

int wmain()
{
	wprintf(L"%hs\n", MORE_TEXT(hah));
	wprintf(L"%hs\n", YET_MORE_TEXT("hah"));
	return 0;
}

Tell the compiler to output the pre-processed file:

You will find that the compiler outputs a .i file in the same location that the .obj files are for that target:

Then look at the file listing, removing the headers:

int wmain()
{
	wprintf(L"%hs\n", "Text");
	wprintf(L"%hs\n", "Text: " "hah");
	wprintf(L"%hs\n", "Text: " "hah");
	return 0;
}

You should see that all the compiler did in this one step is replace the macro name with the body of the macro itself. For the parameters, for the first one, the # translated what was in the () into "", and for the second one it just directly replaced the parameters.

So all you can do with a macro is give a fancy name to a string literal, but you are able to do that with a global variable or constexpr function anyway. What's more, the type of a string literal is defined by the standard to be:

"String"; //const char[7]
L"String"; //const wchar_t[7]
u8"String"; //const char[7]
u"String"; //const char16_t[7]
U"String"; //const char32_t[7]

So technically, you can't even get the right type since any array to pointer degrading would go to const char_type *. (Visual C++ does allow it to go to char_type *, but the standard forbids this with good reason).

So no, if you want to get a general purpose char *, then you need a function, or if you are dead set on a macro, have the macro be the code to create the buffer and initialise it at runtime.


This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

In this link they mentioned that how to create string array using macro, but I could not understand it.

https://stackoverflow.com/questions/44303189/c-macro-to-create-a-string-array

RLWA32 on Tue, 10 Jul 2018 12:03:33


In this link they mentioned that how to create string array using macro, but I could not understand it.

https://stackoverflow.com/questions/44303189/c-macro-to-create-a-string-array

So what do you think is easier for someone else to understand -- simply declaring/initializing a char* array in your code or using preprocessor "macro magic" programming that takes as input virtually the same data that a code-based solution would use?

sgrm123 on Tue, 10 Jul 2018 12:07:18


In this link they mentioned that how to create string array using macro, but I could not understand it.

https://stackoverflow.com/questions/44303189/c-macro-to-create-a-string-array

So what do you think is easier for someone else to understand -- simply declaring/initializing a char* array in your code or using preprocessor "macro magic" programming that takes as input virtually the same data that a code-based solution would use?

Simply declaring/initializing a char* array easy to understand than using preprocessor but I just want to learn creating array using macro.

Guido Franzke on Tue, 10 Jul 2018 12:10:03


Simply declaring/initializing a char* array easy to understand than using preprocessor but I just want to learn creating array using macro.
What efforts have you done until now? How do you declare/initialize a char* array in preprocessor by now?

sgrm123 on Tue, 10 Jul 2018 12:12:38


Simply declaring/initializing a char* array easy to understand than using preprocessor but I just want to learn creating array using macro.

What efforts have you done until now? How do you declare/initialize a char* array in preprocessor by now?
I browsed the internet but not getting clear idea thats why I posted in the forum.

Darran Rowe on Tue, 10 Jul 2018 12:49:18


As I said, all that does is add a pretty name to the string literal, so nothing is really created. That linked post just puts a macro around the string literals, so nothing is created.

If we look at an example, initialising an std::string from a macro, then I'll explain.

#include <string>
#include <cstdio>

#define MY_STRING_MACRO(text) "The text that I added was: " #text

int wmain()
{
	std::string my_string = MY_STRING_MACRO(Hello);
	wprintf(L"%hs\n", my_string.c_str());
	return 0;
}

When this compiles, the pre-processor step does two things, first it replaces the macro with the contents of the macro:

#include <string>
#include <cstdio>

int wmain()
{
	std::string my_string = "The text that I added was: " #Hello;
	wprintf(L"%hs\n", my_string.c_str());
	return 0;
}

It then sees the # and converts this into a string:

#include <string>
#include <cstdio>

int wmain()
{
	std::string my_string = "The text that I added was: " "Hello";
	wprintf(L"%hs\n", my_string.c_str());
	return 0;
}

That is all, the compiler then takes this and compiles it. You may think, "but what about the weird two string literals next to each other". Well, when the compiler sees two string literals next to each other, the compiler will just put them together into one.

#include <string>
#include <cstdio>

int wmain()
{
	std::string my_string = "The text that I added was: " "Hello";
/*
treated the same as
	std::string my_string = "The text that I added was: Hello";
*/
	wprintf(L"%hs\n", my_string.c_str());
	return 0;
}

This is the gist of it. If you want to get things more complicated then it does become more awkward, you generally need a macro that uses a macro to do some of the replacing.

You can mostly do the same with constexpr functions too, that is cleaner.


This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

Darran Rowe on Tue, 10 Jul 2018 13:09:24


For the array part, lets build upon the string macro above.

#include <string>
#include <cstdio>

#define MY_STRING_MACRO(text) #text

#define MY_STRING_ARR(a, b, c, d) {MY_STRING_MACRO(a), MY_STRING_MACRO(b), MY_STRING_MACRO(c), MY_STRING_MACRO(d)}

int wmain()
{
	std::string str_arr[] = MY_STRING_ARR(texta, textb, textc, textd);
	
	wprintf(L"%hs\n", str_arr[0].c_str());
	wprintf(L"%hs\n", str_arr[1].c_str());
	wprintf(L"%hs\n", str_arr[2].c_str());
	wprintf(L"%hs\n", str_arr[3].c_str());
	return 0;
}

The two things that should be obvious here are, 1, the array is fixed to 4 elements, and 2, the array macro just expands the string macro. I shortened the text in the string macro to just the stringized text, but that is not important.

If you pre-process this, the compiler follows the following steps. First it will replace MY_STRING_ARR with the macro body. The parameters will replace the given parameters in the macro body.

#include <string>
#include <cstdio>

#define MY_STRING_MACRO(text) #text

int wmain()
{
	std::string str_arr[] = {MY_STRING_MACRO(texta), MY_STRING_MACRO(textb), MY_STRING_MACRO(textc), MY_STRING_MACRO(textd)};
	
	wprintf(L"%hs\n", str_arr[0].c_str());
	wprintf(L"%hs\n", str_arr[1].c_str());
	wprintf(L"%hs\n", str_arr[2].c_str());
	wprintf(L"%hs\n", str_arr[3].c_str());
	return 0;
}

The syntax for the array initialisation comes from this macro. It will then replace all MY_STRING_MACRO with the body of that macro.

#include <string>
#include <cstdio>

int wmain()
{
	std::string str_arr[] = {#texta, #textb, #textc, #textd};
	
	wprintf(L"%hs\n", str_arr[0].c_str());
	wprintf(L"%hs\n", str_arr[1].c_str());
	wprintf(L"%hs\n", str_arr[2].c_str());
	wprintf(L"%hs\n", str_arr[3].c_str());
	return 0;
}

Then it will use the # to stringize the text following the #.

#include <string>
#include <cstdio>

int wmain()
{
	std::string str_arr[] = {"texta", "textb", "textc", "textd"};
	
	wprintf(L"%hs\n", str_arr[0].c_str());
	wprintf(L"%hs\n", str_arr[1].c_str());
	wprintf(L"%hs\n", str_arr[2].c_str());
	wprintf(L"%hs\n", str_arr[3].c_str());
	return 0;
}

So hopefully you can see that this is just a simple set of text substitutions in the pre-processor phase that does this.

Integer arrays are the same.

Simple Samples on Fri, 13 Jul 2018 20:09:09


Something else you should know about macros is that many experienced C++ programmers don't like macros.

The designer of C++, Bjarne Stroustrup, definitely does not like macros. In the past he had much more in his web site and one thing he said is that he uses "0" instead of "NULL" because NULL is a macro.