How can I output #define value - c++

I am new to this forum so please go easy on me :)
I have the following in my code
#define SYS_SBS 0x02
Whenever I try to use this and try to output,I get 2 as the value, however I want to get SYS_SBS as the output for my program. Is there a way, I can do this.
I have no control over the source code. I just have to output SYS_SBS.
Additional Details: I cannot change some the header files. However I can change the main function in .cpp file. I want the SYS_SBS as the output. I am working with satellites and for all the satellited detected by my receiver, I have to output what type of sattelite they are. In the code all of them are defined with this hexadecimal number. I just want to output SYS_SBS and not 2

#include <stdio.h>
#define SYS_SBS 0x02
#define id(x) #x
int main(){
printf("%s %d\n", id(SYS_SBS), SYS_SBS);
return 0;
}

The C standard provides a stringification operator (add a # in front of the token) that allows you to outuput a specific token.
What's not possible is to convert backwards from a variable's value to this token name as this is lost during translations (as others have mentioned). If you need that kind of conversion, think about a explicit "value2str" function that returns a string representation of a given value:
const char *myType2str(int value)
{
switch (value)
{
case SYS_SBS:
return "SYS_SBS";
default:
return "UNKNOWN VALUE";
}
}
EDIT: According to some comments, stringification is part of the standard. Changed that. Thanks for the hint. Wasn't aware of that.

0x02 is the hexadecimal representation in the source. Once you compiled it, it's just a number (2).
If you want to print it as hex, then, well... print it as hex (eg: use the formatting string "0x%.2x").
Well, you could simply:
printf("SYS_SBS");
But I assume you have a number as "input" (like 2), and want to output the string SYS_SBS, well, that's not directly possible. The best you can do is create a lookup table, eg:
const char* sys_strings[] = { "SYS_EX", "SYS_TEM", "SYS_SBS" };

Related

Looking for a MACRO adding two characters together for switch cases

I'm working on an old network engine and the type of package sent over the network is made up of 2 bytes.
This is more or less human readable form, for example "LO" stands for Login.
In the part that reads the data there is an enormous switch, like this:
short sh=(((int)ad.cData[p])<<8)+((int)ad.cData[p+1]);
switch(sh)
{
case CMD('M','D'):
..some code here
break
where CMD is a define:
#define CMD(a,b) ((a<<8)+b)
I know there are better ways but just to clean up a bit and also to be able to search for the tag (say "LO") more easily (and not search for different types of "'L','O'" or "'L' , 'O'" or the occasional "'L', 'O'" <- spaces make it hard to search) I tried to make a MACRO for the switch so I could use "LO" instead of the define but I just can't get it to compile.
So here is the question: how do you change the #define to a macro that I can use like this instead:
case CMD("MD"):
..some code here
break
It started out as a little subtask to make life a little bit easier but now I can't get it out of my head, thanks for any help!
Cheers!
[edit] The code works, it the world that's wrong! ie. Visual Studio 2010 has a bug concerning this. No wonder I cut my teeth on it.
Macro-based solution
A string-literal is really an instance of char const[N] where N is the length of the string, including the terminating null-byte. With this in mind you can easily access any character within the string-literal by using string-literal[idx] to specify that you'd like to read the character stored at offset idx.
#define CMD(str) ((str[0]<<8)+str[1])
CMD("LO") => (("LO"[0]<<8)+"LO"[1]) => (('L'<<8)+'0')
You should however keep in mind that there's nothing preventing your from using the above macro with a string which is shorter than that of length 2, meaning that you can run into undefined-behavior if you try to read an offset which is not actually valid.
RECOMMENDED: C++11, use a constexpr function
You could create a function usable in constant-expressions (and with that, in case-labels), with a parameter of reference to const char[3], which is the "real" type of your string-literal "FO".
constexpr short cmd (char const(&ref)[3]) {
return (ref[0]<<8) + ref[1];
}
int main () {
short data = ...;
switch (data) {
case cmd("LO"):
...
}
}
C++11 and user-defined literals
In C++11 we were granted the possibility to define user-defined literals. This will make your code far easier to maintain and interpret, as well as having it be safer to use:
#include <stdexcept>
constexpr short operator"" _cmd (char const * s, unsigned long len) {
return len != 2 ? throw std::invalid_argument ("") : ((s[0]<<8)+s[1]);
}
int main () {
short data = ...;
switch (data) {
case "LO"_cmd:
...
}
}
The value associated with a case-label must be yield through a constant-expression. It might look like the above might throw an exception during runtime, but since a case-label is constant-expression the compiler must be able to evaluate "LO"_cmd during translation.
If this is not possible, as in "FOO"_cmd, the compiler will issue a diagnostic saying that the code is ill-formed.

QSettings does not differentiate between string and int values

I am writing and reading string and int values using a file-backed QSettings object.
When I later try to read the values from a different process, the values are read as strings instead of int.
This is the code I am using to write values:
QSettings settings("TestQSettings.ini", QSettings::IniFormat);
settings.setValue("AAA",QString("111"));
settings.setValue("BBB",222);
This is the file created:
[General]
AAA=111
BBB=222
This is the code I am using to read values:
QVariant qvar = settings.value("AAA");
std::cout << "AAA type " << qvar.type() << std::endl;
qvar = settings.value("BBB");
std::cout << "BBB type " << qvar.type() << std::endl;
If I run this code from the same process:
AAA type 10
BBB type 2
If I run this code from a different process:
AAA type 10
BBB type 10
I know it's possible to convert the types after they have been read.
Unfortunately, this solution will require modifying Windows legacy cross-platform code which I prefer not to modify, for example multiple calls to RegQueryValueEx().
Is it possible to store and read the type information for strings and integers?
For example, Strings will have quotes "" and integers will not:
[General]
AAA="111"
BBB=222
This problem is present on both Qt 4 and Qt 5, on Linux.
Whoa whoa, are you using .ini files or the registry?
With .ini files it's obviously impossible to know what the type was, since it's all a string. You can attempt conversion of the variant to an integer (don't use canConvert!), and assume it's an integer if it converts into one.
With the registry, QSettings will work as you expect it to.
I really don't see what the problem is. Don't use .ini files if you wish to retain type information. You'd face exactly the same problems if you wrote the code by hand in a platform-dependent manner.
You can explicitly write quoted strings into the .ini files, and check for presence of quotes when reading them back. If the quotes are not present, you can try conversion to an integer.
I solved this problem for a component which needs to save and restore variants of arbitrary type, without knowing what its clients expect. The solution was to store the variant's typeName() alongside each value:
void store(QSettings& settings, const QString& key, const QVariant& value)
{
settings.setValue(key+"value", value);
settings.setValue(key+"type", value.typeName());
}
When reading back, we also read the type name, and convert() the variant if it's not already the correct type, before returning it.
QVariant retrieve(const QSettings& settings, const QString& key)
{
auto value = settings.value(key+"value");
const auto typeName = settings.value(key+"type").toString();
const bool wasNull = value.isNull(); // NOTE 1
const auto t = QMetaType::type(typeName.toUtf8()); // NOTE 2
if (value.userType() != t && !value.convert(t) && !wasNull) {
// restore value that was cleared by the failed convert()
value = settings.value(key+"value");
qWarning() << "Failed to convert value" << value << "to" << typeName;
}
return value;
}
Notes
The wasNull variable is in there because of this niggle of convert():
Warning: For historical reasons, converting a null QVariant results in a null value of the desired type (e.g., an empty string for QString) and a result of false.
In this case, we need to ignore the misleading return value, and keep the successfully-converted null variant of the correct type.
It's not clear that UTF-8 is the correct encoding for QMetaType names (perhaps local 8-bit is assumed?); my types are all ASCII, so I just use toLatin1() instead, which might be faster. If it were an issue, I'd use QString::fromLatin1 in the store() method (instead of implicit char* to QString conversion), to ensure a clean round-trip.
If the type name is not found, t will be QMetaType::UnknownType; that's okay, because convert() will then fail, and we'll return the unconverted variant (or a null). It's not great, but it's a corner case that won't happen in normal usage, and my system will recover reasonably quickly.
Turns out the solution was very simple.
When values are written to the INI file, the type is known.
I am appending to the value "\"STRING right before SetValue
When values are read back from the INI file.
I verify that string types have the above postfix.
If they do, I chop the postfix off.
If they don't I assume they are integers instead of strings.
Works like a charm!
Thanks to you all and especially #Kuba Ober for practically handing out the solution.

printf with std::string?

My understanding is that string is a member of the std namespace, so why does the following occur?
#include <iostream>
int main()
{
using namespace std;
string myString = "Press ENTER to quit program!";
cout << "Come up and C++ me some time." << endl;
printf("Follow this command: %s", myString);
cin.get();
return 0;
}
Each time the program runs, myString prints a seemingly random string of 3 characters, such as in the output above.
C++23 Update
We now finally have std::print as a way to use std::format for output directly:
#include <print>
#include <string>
int main() {
// ...
std::print("Follow this command: {}", myString);
// ...
}
This combines the best of both approaches.
Original Answer
It's compiling because printf isn't type safe, since it uses variable arguments in the C sense1. printf has no option for std::string, only a C-style string. Using something else in place of what it expects definitely won't give you the results you want. It's actually undefined behaviour, so anything at all could happen.
The easiest way to fix this, since you're using C++, is printing it normally with std::cout, since std::string supports that through operator overloading:
std::cout << "Follow this command: " << myString;
If, for some reason, you need to extract the C-style string, you can use the c_str() method of std::string to get a const char * that is null-terminated. Using your example:
#include <iostream>
#include <string>
#include <stdio.h>
int main()
{
using namespace std;
string myString = "Press ENTER to quit program!";
cout << "Come up and C++ me some time." << endl;
printf("Follow this command: %s", myString.c_str()); //note the use of c_str
cin.get();
return 0;
}
If you want a function that is like printf, but type safe, look into variadic templates (C++11, supported on all major compilers as of MSVC12). You can find an example of one here. There's nothing I know of implemented like that in the standard library, but there might be in Boost, specifically boost::format.
[1]: This means that you can pass any number of arguments, but the function relies on you to tell it the number and types of those arguments. In the case of printf, that means a string with encoded type information like %d meaning int. If you lie about the type or number, the function has no standard way of knowing, although some compilers have the ability to check and give warnings when you lie.
Please don't use printf("%s", your_string.c_str());
Use cout << your_string; instead. Short, simple and typesafe. In fact, when you're writing C++, you generally want to avoid printf entirely -- it's a leftover from C that's rarely needed or useful in C++.
As to why you should use cout instead of printf, the reasons are numerous. Here's a sampling of a few of the most obvious:
As the question shows, printf isn't type-safe. If the type you pass differs from that given in the conversion specifier, printf will try to use whatever it finds on the stack as if it were the specified type, giving undefined behavior. Some compilers can warn about this under some circumstances, but some compilers can't/won't at all, and none can under all circumstances.
printf isn't extensible. You can only pass primitive types to it. The set of conversion specifiers it understands is hard-coded in its implementation, and there's no way for you to add more/others. Most well-written C++ should use these types primarily to implement types oriented toward the problem being solved.
It makes decent formatting much more difficult. For an obvious example, when you're printing numbers for people to read, you typically want to insert thousands separators every few digits. The exact number of digits and the characters used as separators varies, but cout has that covered as well. For example:
std::locale loc("");
std::cout.imbue(loc);
std::cout << 123456.78;
The nameless locale (the "") picks a locale based on the user's configuration. Therefore, on my machine (configured for US English) this prints out as 123,456.78. For somebody who has their computer configured for (say) Germany, it would print out something like 123.456,78. For somebody with it configured for India, it would print out as 1,23,456.78 (and of course there are many others). With printf I get exactly one result: 123456.78. It is consistent, but it's consistently wrong for everybody everywhere. Essentially the only way to work around it is to do the formatting separately, then pass the result as a string to printf, because printf itself simply will not do the job correctly.
Although they're quite compact, printf format strings can be quite unreadable. Even among C programmers who use printf virtually every day, I'd guess at least 99% would need to look things up to be sure what the # in %#x means, and how that differs from what the # in %#f means (and yes, they mean entirely different things).
use myString.c_str() if you want a c-like string (const char*) to use with printf
thanks
Use std::printf and c_str()
example:
std::printf("Follow this command: %s", myString.c_str());
You can use snprinft to determine the number of characters needed and allocate a buffer of the right size.
int length = std::snprintf(nullptr, 0, "There can only be %i\n", 1 );
char* str = new char[length+1]; // one more character for null terminator
std::snprintf( str, length + 1, "There can only be %i\n", 1 );
std::string cppstr( str );
delete[] str;
This is a minor adaption of an example on cppreference.com
printf accepts a variable number of arguments. Those can only have Plain Old Data (POD) types. Code that passes anything other than POD to printf only compiles because the compiler assumes you got your format right. %s means that the respective argument is supposed to be a pointer to a char. In your case it is an std::string not const char*. printf does not know it because the argument type goes lost and is supposed to be restored from the format parameter. When turning that std::string argument into const char* the resulting pointer will point to some irrelevant region of memory instead of your desired C string. For that reason your code prints out gibberish.
While printf is an excellent choice for printing out formatted text, (especially if you intend to have padding), it can be dangerous if you haven't enabled compiler warnings. Always enable warnings because then mistakes like this are easily avoidable. There is no reason to use the clumsy std::cout mechanism if the printf family can do the same task in a much faster and prettier way. Just make sure you have enabled all warnings (-Wall -Wextra) and you will be good. In case you use your own custom printf implementation you should declare it with the __attribute__ mechanism that enables the compiler to check the format string against the parameters provided.
The main reason is probably that a C++ string is a struct that includes a current-length value, not just the address of a sequence of chars terminated by a 0 byte. Printf and its relatives expect to find such a sequence, not a struct, and therefore get confused by C++ strings.
Speaking for myself, I believe that printf has a place that can't easily be filled by C++ syntactic features, just as table structures in html have a place that can't easily be filled by divs. As Dykstra wrote later about the goto, he didn't intend to start a religion and was really only arguing against using it as a kludge to make up for poorly-designed code.
It would be quite nice if the GNU project would add the printf family to their g++ extensions.
Printf is actually pretty good to use if size matters. Meaning if you are running a program where memory is an issue, then printf is actually a very good and under rater solution. Cout essentially shifts bits over to make room for the string, while printf just takes in some sort of parameters and prints it to the screen. If you were to compile a simple hello world program, printf would be able to compile it in less than 60, 000 bits as opposed to cout, it would take over 1 million bits to compile.
For your situation, id suggest using cout simply because it is much more convenient to use. Although, I would argue that printf is something good to know.
Here’s a generic way of doing it.
#include <string>
#include <stdio.h>
auto print_helper(auto const & t){
return t;
}
auto print_helper(std::string const & s){
return s.c_str();
}
std::string four(){
return "four";
}
template<class ... Args>
void print(char const * fmt, Args&& ...args){
printf(fmt, print_helper(args) ...);
}
int main(){
std::string one {"one"};
char const * three = "three";
print("%c %d %s %s, %s five", 'c', 3+4, one + " two", three, four());
}

Encrypting / obfuscating a string literal at compile-time

I want to encrypt/encode a string at compile time so that the original string does not appear in the compiled executable.
I've seen several examples but they can't take a string literal as argument. See the following example:
template<char c> struct add_three {
enum { value = c+3 };
};
template <char... Chars> struct EncryptCharsA {
static const char value[sizeof...(Chars) + 1];
};
template<char... Chars>
char const EncryptCharsA<Chars...>::value[sizeof...(Chars) + 1] = {
add_three<Chars>::value...
};
int main() {
std::cout << EncryptCharsA<'A','B','C'>::value << std::endl;
// prints "DEF"
}
I don't want to provide each character separately like it does. My goal is to pass a string literal like follows:
EncryptString<"String to encrypt">::value
There's also some examples like this one:
#define CRYPT8(str) { CRYPT8_(str "\0\0\0\0\0\0\0\0") }
#define CRYPT8_(str) (str)[0] + 1, (str)[1] + 2, (str)[2] + 3, (str)[3] + 4, (str)[4] + 5, (str)[5] + 6, (str)[6] + 7, (str)[7] + 8, '\0'
// calling it
const char str[] = CRYPT8("ntdll");
But it limits the size of the string.
Is there any way to achieve what I want?
I think this question deserves an updated answer.
When I asked this question several years ago, I didn't consider the difference between obfuscation and encryption. Had I known this difference then, I'd have included the term Obfuscation in the title before.
C++11 and C++14 have features that make it possible to implement compile-time string obfuscation (and possibly encryption, although I haven't tried that yet) in an effective and reasonably simple way, and it's already been done.
ADVobfuscator is an obfuscation library created by Sebastien Andrivet that uses C++11/14 to generate compile-time obfuscated code without using any external tool, just C++ code. There's no need to create extra build steps, just include it and use it. I don't know a better compile-time string encryption/obfuscation implementation that doesn't use external tools or build steps. If you do, please share.
It not only obuscates strings, but it has other useful things like a compile-time FSM (Finite State Machine) that can randomly obfuscate function calls, and a compile-time pseudo-random number generator, but these are out of the scope of this answer.
Here's a simple string obfuscation example using ADVobfuscator:
#include "MetaString.h"
using namespace std;
using namespace andrivet::ADVobfuscator;
void Example()
{
/* Example 1 */
// here, the string is compiled in an obfuscated form, and
// it's only deobfuscated at runtime, at the very moment of its use
cout << OBFUSCATED("Now you see me") << endl;
/* Example 2 */
// here, we store the obfuscated string into an object to
// deobfuscate whenever we need to
auto narrator = DEF_OBFUSCATED("Tyler Durden");
// note: although the function is named `decrypt()`, it's still deobfuscation
cout << narrator.decrypt() << endl;
}
You can replace the macros DEF_OBFUSCATED and OBFUSCATED with your own macros. Eg.:
#define _OBF(s) OBFUSCATED(s)
...
cout << _OBF("klapaucius");
How does it work?
If you take a look at the definition of these two macros in MetaString.h, you will see:
#define DEF_OBFUSCATED(str) MetaString<andrivet::ADVobfuscator::MetaRandom<__COUNTER__, 3>::value, andrivet::ADVobfuscator::MetaRandomChar<__COUNTER__>::value, Make_Indexes<sizeof(str) - 1>::type>(str)
#define OBFUSCATED(str) (DEF_OBFUSCATED(str).decrypt())
Basically, there are three different variants of the MetaString class (the core of the string obfuscation). Each has its own obfuscation algorithm. One of these three variants is chosen randomly at compile-time, using the library's pseudo-random number generator (MetaRandom), along with a random char that is used by the chosen algorithm to xor the string characters.
"Hey, but if we do the math, 3 algorithms * 255 possible char keys (0 is not used) = 765 variants of the obfuscated string"
You're right. The same string can only be obfuscated in 765 different ways. If you have a reason to need something safer (you're paranoid / your application demands increased security) you can extend the library and implement your own algorithms, using stronger obfuscation or even encryption (White-Box cryptography is in the lib's roadmap).
Where / how does it store the obfuscated strings?
One thing I find interesting about this implementation is that it doesn't store the obfuscated string in the data section of the executable.
Instead, it is statically stored into the MetaString object itself (on the stack) and the algorithm decodes it in place at runtime. This approach makes it much harder to find the obfuscated strings, statically or at runtime.
You can dive deeper into the implementation by yourself. That's a very good basic obfuscation solution and can be a starting point to a more complex one.
Save yourself a heap of trouble down the line with template metaprogramming and just write a stand alone program that encrypts the string and produces a cpp source file which is then compiled in. This program would run before you compile and would produce a cpp and/or header file that would contain the encrypted string for you to use.
So here is what you start with:
encrypted_string.cpp and encrypted_string.h (which are blank)
A script or standalone app that takes a text file as an input and over writes encrypted_string.cpp and encrypted_string.h
If the script fails, your compiling will fail because there will be references in your code to a variable that does not exist. You could get smarter, but that's enough to get you started.
The reason why the examples you found can't take string literals as template argument is because it's not allowed by the ISO C++ standard. That's because, even though c++ has a string class, a string literal is still a const char *. So, you can't, or shouldn't, alter it (leads to undefined behaviour), even if you can access the characters of such an compile-time string literal.
The only way I see is using defines, as they are handled by the preprocessor before the compiler. Maybe boost will give you a helping hand in that case.
A macro based solution would be to take a variadic argument and pass in each part of the string as a single token. Then stringify the token and encrypt it and concatenate all tokens. The end result would look something like this
CRYPT(m y _ s t r i n g)
Where _ is some placeholder for a whitespace character literal. Horribly messy and I would prefer every other solution over this.
Something like this could do it although the Boost.PP Sequence isn't making it any prettier.
#include <iostream>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#define GARBLE(x) GARBLE_ ## x
#define GARBLE_a x
#define GARBLE_b y
#define GARBLE_c z
#define SEQ (a)(b)(c)
#define MACRO(r, data, elem) BOOST_PP_STRINGIZE(GARBLE(elem))
int main() {
const char* foo = BOOST_PP_SEQ_FOR_EACH(MACRO, _, SEQ);
std::cout << foo << std::endl;
}

C/C++ line number

In the sake of debugging purposes, can I get the line number in C/C++ compilers?
(standard way or specific ways for certain compilers)
e.g
if(!Logical)
printf("Not logical value at line number %d \n",LineNumber);
// How to get LineNumber without writing it by my hand?(dynamic compilation)
You should use the preprocessor macro __LINE__ and __FILE__. They are predefined macros and part of the C/C++ standard. During preprocessing, they are replaced respectively by a constant string holding an integer representing the current line number and by the current file name.
Others preprocessor variables :
__func__ : function name (this is part of C99, not all C++ compilers support it)
__DATE__ : a string of form "Mmm dd yyyy"
__TIME__ : a string of form "hh:mm:ss"
Your code will be :
if(!Logical)
printf("Not logical value at line number %d in file %s\n", __LINE__, __FILE__);
As part of the C++ standard there exists some pre-defined macros that you can use. Section 16.8 of the C++ standard defines amongst other things, the __LINE__ macro.
__LINE__: The line number of the current source line (a decimal
constant).
__FILE__: The presumed name of the source file (a character string
literal).
__DATE__: The date of translation of the source file (a character string
literal...)
__TIME__: The time of translation of the source file (a character string
literal...)
__STDC__: Whether__STDC__ is predefined
__cplusplus: The name __cplusplus is defined to the value 199711L when
compiling a C ++ translation unit
So your code would be:
if(!Logical)
printf("Not logical value at line number %d \n",__LINE__);
You could use a macro with the same behavior as printf(),
except that it also includes debug information such as
function name, class, and line number:
#include <cstdio> //needed for printf
#define print(a, args...) printf("%s(%s:%d) " a, __func__,__FILE__, __LINE__, ##args)
#define println(a, args...) print(a "\n", ##args)
These macros should behave identically to printf(), while including java stacktrace-like information. Here's an example main:
void exampleMethod() {
println("printf() syntax: string = %s, int = %d", "foobar", 42);
}
int main(int argc, char** argv) {
print("Before exampleMethod()...\n");
exampleMethod();
println("Success!");
}
Which results in the following output:
main(main.cpp:11) Before exampleMethod()...
exampleMethod(main.cpp:7) printf() syntax: string = foobar, int = 42
main(main.cpp:13) Success!
C++20 offers a new way to achieve this by using std::source_location. This is currently accessible in gcc an clang as std::experimental::source_location with #include <experimental/source_location>.
The problem with macros like __LINE__ is that if you want to create for example a logging function that outputs the current line number along with a message, you always have to pass __LINE__ as a function argument, because it is expanded at the call site.
Something like this:
void log(const std::string msg) {
std::cout << __LINE__ << " " << msg << std::endl;
}
Will always output the line of the function declaration and not the line where log was actually called from.
On the other hand, with std::source_location you can write something like this:
#include <experimental/source_location>
using std::experimental::source_location;
void log(const std::string msg, const source_location loc = source_location::current())
{
std::cout << loc.line() << " " << msg << std::endl;
}
Here, loc is initialized with the line number pointing to the location where log was called.
You can try it online here.
Use __LINE__ (that's double-underscore LINE double-underscore), the preprocessor will replace it with the line number on which it is encountered.
Checkout __FILE__ and __LINE__ macros
Try __FILE__ and __LINE__.
You might also find __DATE__ and __TIME__ useful.
Though unless you have to debug a program on the clientside and thus need to log these informations you should use normal debugging.
For those who might need it, a "FILE_LINE" macro to easily print file and line:
#define STRINGIZING(x) #x
#define STR(x) STRINGIZING(x)
#define FILE_LINE __FILE__ ":" STR(__LINE__)
Since i'm also facing this problem now and i cannot add an answer to a different but also valid question asked here,
i'll provide an example solution for the problem of:
getting only the line number of where the function has been called in C++ using templates.
Background: in C++ one can use non-type integer values as a template argument. This is different than the typical usage of data types as template arguments.
So the idea is to use such integer values for a function call.
#include <iostream>
class Test{
public:
template<unsigned int L>
int test(){
std::cout << "the function has been called at line number: " << L << std::endl;
return 0;
}
int test(){ return this->test<0>(); }
};
int main(int argc, char **argv){
Test t;
t.test();
t.test<__LINE__>();
return 0;
}
Output:
the function has been called at line number: 0
the function has been called at line number: 16
One thing to mention here is that in C++11 Standard it's possible to give default template values for functions using template. In pre C++11 default values for non-type arguments seem to only work for class template arguments. Thus, in C++11, there would be no need to have duplicate function definitions as above. In C++11 its also valid to have const char* template arguments but its not possible to use them with literals like __FILE__ or __func__ as mentioned here.
So in the end if you're using C++ or C++11 this might be a very interesting alternative than using macro's to get the calling line.
Use __LINE__, but what is its type?
LINE The presumed line number (within the current source file) of the current source line (an integer constant).
As an integer constant, code can often assume the value is __LINE__ <= INT_MAX and so the type is int.
To print in C, printf() needs the matching specifier: "%d". This is a far lesser concern in C++ with cout.
Pedantic concern: If the line number exceeds INT_MAX1 (somewhat conceivable with 16-bit int), hopefully the compiler will produce a warning. Example:
format '%d' expects argument of type 'int', but argument 2 has type 'long int' [-Wformat=]
Alternatively, code could force wider types to forestall such warnings.
printf("Not logical value at line number %ld\n", (long) __LINE__);
//or
#include <stdint.h>
printf("Not logical value at line number %jd\n", INTMAX_C(__LINE__));
Avoid printf()
To avoid all integer limitations: stringify. Code could directly print without a printf() call: a nice thing to avoid in error handling2 .
#define xstr(a) str(a)
#define str(a) #a
fprintf(stderr, "Not logical value at line number %s\n", xstr(__LINE__));
fputs("Not logical value at line number " xstr(__LINE__) "\n", stderr);
1 Certainly poor programming practice to have such a large file, yet perhaps machine generated code may go high.
2 In debugging, sometimes code simply is not working as hoped. Calling complex functions like *printf() can itself incur issues vs. a simple fputs().