Macros argument order matters? - c++

When i compile the below program following error is generated by the compiler.
example.cpp:12:13: error: invalid operands to binary expression ('const char *' and 'const char *')
cout << JMP(to_string(10)) << endl;
^~~~~~~~~~~~~~~~~~
example.cpp:6:34: note: expanded from macro 'JMP'
#define JMP(add) "DEFAULT is : " + DEFAULT + " JMP is : " + add
~~~~~~~~~~~~~~~ ^ ~~~~~~~
#include <iostream>
#include <string>
#define DEFAULT "00000"
#define JMP(add) "DEFAULT is : " + DEFAULT + " JMP is : " + add
using namespace std;
int main()
{
cout << JMP(to_string(10)) << endl;
return 0;
}
Whereas the below program compiles properly
#include <iostream>
#include <string>
#define DEFAULT "00000"
#define JMP(add) "JMP is : " + add + "DEFAULT is : " + DEFAULT
using namespace std;
int main()
{
cout << JMP(to_string(10)) << endl;
return 0;
}
Why the order of argument present in the macro body matters ?

Try to get rid of the + to concatenate char array literals:
#define JMP(add) "DEFAULT is : " DEFAULT " JMP is : " add
NOTE:
Since add will expand to a std::string value (to_string(10)) from your sample, this won't work either. You'll need to call the macro like this:
cout << JMP("10") << endl;
An alternate solution would be making the parts std::string instances:
#define JMP(add) std::string("DEFAULT is : " DEFAULT " JMP is : ") + add

The error is telling you that the operands given to the binary expression (i.e. + operator) are not of expected types. This operator is expecting a const string & (or a string & using C++ 11) for at least one of its operands. That plus left to right evaluation is why it works when you switch the order.
cout << to_string(10) + " is the JUMP" << endl; // having valid operands, + operator returns a string object
cout << "JUMP is : " + to_string(10) << endl; // same here
cout << "DEFAULT is : " + "00000" << endl; // no bueno: both operands are const char pointers
Provided that you have a const string & as a starter*, you can keep concatenating const char *s all day long:
cout << "JUMP is : " + to_string(10) + " DEFAULT is : " + "00000" + "game is " + "concentration, " + "category is " + "..." << endl;
So, this actually is not about order of macro arguments but about strings, char pointers, concatenation, associativity, and operators.
*as in a sports game.

Related

Why does Visual Studio output this in my C++ program (adding string and character)? [duplicate]

The code successfully compiles it but I can't understand why, for certain values of number, the program crashes and for other values it doesn't. Could someone explain the behavior of adding a long int with a char* that the compiler uses?
#include <iostream>
int main()
{
long int number=255;
std::cout<< "Value 1 : " << std::flush << ("" + number) << std::flush << std::endl;
number=15155;
std::cout<< "Value 2 : " << std::flush << ("" + number) << std::flush << std::endl;
return 0;
}
Test results:
Value 1 : >
Value 2 : Segmentation fault
Note: I'm not looking for a solution on how to add a string with a number.
In C++, "" is a const char[1] array, which decays into a const char* pointer to the first element of the array (in this case, the string literal's '\0' nul terminator).
Adding an integer to a pointer performs pointer arithmetic, which will advance the memory address in the pointer by the specified number of elements of the type the pointer is declared as (in this case, char).
So, in your example, ... << ("" + number) << ... is equivalent to ... << &""[number] << ..., or more generically:
const char *ptr = &""[0];
ptr = reinterpret_cast<const char*>(
reinterpret_cast<const uintptr_t>(ptr)
+ (number * sizeof(char))
);
... << ptr << ...
Which means you are going out of bounds of the array when number is any value other than 0, thus your code has undefined behavior and anything could happen when operator<< tries to dereference the invalid pointer you give it.
Unlike in many scripting languages, ("" + number) is not the correct way to convert an integer to a string in C++. You need to use an explicit conversion function instead, such as std::to_string(), eg:
#include <iostream>
#include <string>
int main()
{
long int number = 255;
std::cout << "Value 1 : " << std::flush << std::to_string(number) << std::flush << std::endl;
number = 15155;
std::cout << "Value 2 : " << std::flush << std::to_string(number) << std::flush << std::endl;
return 0;
}
Or, you can simply let std::ostream::operator<< handle that conversion for you, eg:
#include <iostream>
int main()
{
long int number = 255;
std::cout<< "Value 1 : " << std::flush << number << std::flush << std::endl;
number = 15155;
std::cout<< "Value 2 : " << std::flush << number << std::flush << std::endl;
return 0;
}
Pointer arithmetic is the culprit.
A const char* is accepted by operator<<, but will not point to a valid memory address in your example.
If you switch on -Wall, you will see a compiler warning about that:
main.cpp: In function 'int main()':
main.cpp:6:59: warning: array subscript 255 is outside array bounds of 'const char [1]' [-Warray-bounds]
6 | std::cout<< "Value 1 : " << std::flush << ("" + number) << std::flush << std::endl;
| ^
main.cpp:8:59: warning: array subscript 15155 is outside array bounds of 'const char [1]' [-Warray-bounds]
8 | std::cout<< "Value 2 : " << std::flush << ("" + number) << std::flush << std::endl;
| ^
Value 1 : q
Live Demo

What's the behaviour of "" + number and why it compile?

The code successfully compiles it but I can't understand why, for certain values of number, the program crashes and for other values it doesn't. Could someone explain the behavior of adding a long int with a char* that the compiler uses?
#include <iostream>
int main()
{
long int number=255;
std::cout<< "Value 1 : " << std::flush << ("" + number) << std::flush << std::endl;
number=15155;
std::cout<< "Value 2 : " << std::flush << ("" + number) << std::flush << std::endl;
return 0;
}
Test results:
Value 1 : >
Value 2 : Segmentation fault
Note: I'm not looking for a solution on how to add a string with a number.
In C++, "" is a const char[1] array, which decays into a const char* pointer to the first element of the array (in this case, the string literal's '\0' nul terminator).
Adding an integer to a pointer performs pointer arithmetic, which will advance the memory address in the pointer by the specified number of elements of the type the pointer is declared as (in this case, char).
So, in your example, ... << ("" + number) << ... is equivalent to ... << &""[number] << ..., or more generically:
const char *ptr = &""[0];
ptr = reinterpret_cast<const char*>(
reinterpret_cast<const uintptr_t>(ptr)
+ (number * sizeof(char))
);
... << ptr << ...
Which means you are going out of bounds of the array when number is any value other than 0, thus your code has undefined behavior and anything could happen when operator<< tries to dereference the invalid pointer you give it.
Unlike in many scripting languages, ("" + number) is not the correct way to convert an integer to a string in C++. You need to use an explicit conversion function instead, such as std::to_string(), eg:
#include <iostream>
#include <string>
int main()
{
long int number = 255;
std::cout << "Value 1 : " << std::flush << std::to_string(number) << std::flush << std::endl;
number = 15155;
std::cout << "Value 2 : " << std::flush << std::to_string(number) << std::flush << std::endl;
return 0;
}
Or, you can simply let std::ostream::operator<< handle that conversion for you, eg:
#include <iostream>
int main()
{
long int number = 255;
std::cout<< "Value 1 : " << std::flush << number << std::flush << std::endl;
number = 15155;
std::cout<< "Value 2 : " << std::flush << number << std::flush << std::endl;
return 0;
}
Pointer arithmetic is the culprit.
A const char* is accepted by operator<<, but will not point to a valid memory address in your example.
If you switch on -Wall, you will see a compiler warning about that:
main.cpp: In function 'int main()':
main.cpp:6:59: warning: array subscript 255 is outside array bounds of 'const char [1]' [-Warray-bounds]
6 | std::cout<< "Value 1 : " << std::flush << ("" + number) << std::flush << std::endl;
| ^
main.cpp:8:59: warning: array subscript 15155 is outside array bounds of 'const char [1]' [-Warray-bounds]
8 | std::cout<< "Value 2 : " << std::flush << ("" + number) << std::flush << std::endl;
| ^
Value 1 : q
Live Demo

While left shift operator (<<) using before std::cout , what does it work for?

Those code lines:
std::cout << "observerIndex : " <<
std::cout << pobserverIndex -> observerInt() ;
Generate the compiler error below:
file.C:2917:37: error: no match for 'operator<<' (operand types are 'std::basic_ostream<char>' and 'std::basic_ostream<char>')
std::cout << "observerIndex : " <<
^
Could anyone please tell me what left shift operator(<<) is doing on there (before std::cout << pobserverIndex -> observerInt())?
You appear to be missing a semicolon at the end of your first statement, plus you are repeating std::cout.
You need to use
std::cout << "observerIndex: " << pobserverIndex -> observerInt();
A variant like
std::cout << "a" << std::cout<< "b";
is outputting the address of the object cout in the std namespace, formatted as hexadecimal, between the strings "a" and "b".

c++: concat constant string with macro-defined string

I want to concat the constant string and the macro defined string.
#define DEEP_DRIVE_NET "C:/Users/tumh/hookv/deep_drive_model.prototxt"
#define DEEP_DRIVE_WEIGHT "C:/Users/tumh/hookv/caffe_deep_drive_train_iter_35352.caffemodel"
CHECK(file_exist(DEEP_DRIVE_WEIGHT)) << "Net Weight " + DEEP_DRIVE_WEIGHT + " Not Found";
CHECK(file_exist(DEEP_DRIVE_NET)) << "Net definition " + DEEP_DRIVE_NET + " Not Found";
the compile error from msvc 2013 compiler is
C:\Users\tumh\hookv\samples\Test\Inference.cpp(28): error C2110: '+' : cannot add two pointers [C:\Users\tumh\hookv\build\NativeTrainer.vcxproj]
C:\Users\tumh\hookv\samples\Test\Inference.cpp(29): error C2110: '+' : cannot add two pointers [C:\Users\tumh\hookv\build\NativeTrainer.vcxproj]
How can I concatenate such strings?
Thanks.
Just omit the + operations to concatenate c-style string literals:
CHECK(file_exist(DEEP_DRIVE_WEIGHT)) << "Net Weight " DEEP_DRIVE_WEIGHT " Not Found";
CHECK(file_exist(DEEP_DRIVE_NET)) << "Net definition " DEEP_DRIVE_NET " Not Found";

Concatenation operator in C++?

I have an application in which I need to combine strings within a variable like so:
int int_arr[4];
int_arr[1] = 123;
int_arr[2] = 456;
int_arr[3] = 789;
int_arr[4] = 10;
std::string _string = "Text " + int_arr[1] + " Text " + int_arr[2] + " Text " + int_arr[3] + " Text " + int_arr[4];
It gives me the compile error
Error C2210: '+' Operator cannot add pointers" on the second string of the expression.
As far as I can tell I am combining string literals and integers, not pointers.
Is there another concatenation operator that I should be using? Or is the expression just completely wrong and should figure out another way to implement this?
BTW I am using Visual Studio 2010
Neither C nor C++ allow concatenation of const char * and int. Even C++'s std::string, doesn't concatenate integers. Use streams instead:
std::stringstream ss;
ss << "Text " << int_arr[1] << " Text " << int_arr[2] << " Text " << int_arr[3] << " Text " << int_arr[4];
std::string _string = ss.str();
You can do this in Java since it uses the toString() method automatically on each part.
If you want to do it the same way in C++, you'll have to explicitly convert those integer to strings in order for this to work.
Something like:
#include <iostream>
#include <sstream>
std::string intToStr (int i) {
std::ostringstream s;
s << i;
return s.str();
}
int main (void) {
int var = 7;
std::string s = "Var is '" + intToStr(var) + "'";
std::cout << s << std::endl;
return 0;
}
Of course, you can just use:
std::ostringstream os;
os << "Var is '" << var << "'";
std::string s = os.str();
which is a lot easier.
A string literal becomes a pointer in this context. Not a std::string. (Well, to be pedantically correct, string literals are character arrays, but the name of an array has an implicit conversion to a pointer. One predefined form of the + operator takes a pointer left-argument and an integral right argument, which is the best match, so the implicit conversion takes place here. No user-defined conversion can ever take precedence over this built-in conversion, according to the C++ overloading rules.).
You should study a good C++ book, we have a list here on SO.
A string literal is an expression returning a pointer const char*.
std::stringstream _string_stream;
_string_stream << "Text " << int_arr[1] << " Text " << int_arr[2] << " Text " << int_arr[3] << " Text " << int_arr[4];
std::string _string = _string_stream.str();