-3

my code example is simple:

#include <fstream>  

int main() {
    int printDebug=1; // 1 - turn on, 0 -turn off.

    if (printDebug==1){
            ofstream output_file("outputDelta.txt"); // create output file
    }
    for (int i = 0; i < 1e2; i++){
            if (printDebug==1){
                output_file << i <<"\n"; 
            }
    }
    return 0;
}

it doesn't compile, as "error: 'output_file' was not declared in this scope". My whole idea is not to declare any output_file if I'm not in printDebug mode. I don't want to create empty outputs or allocate memory for nothing. How would you solve it?

Michael L.
  • 443
  • 4
  • 14
  • You cannot arbitrarily put statements outside of any function body. – πάντα ῥεῖ May 18 '23 at 11:14
  • 1
    `ofstream f; f << "foo";` is not writing to a file – 463035818_is_not_an_ai May 18 '23 at 11:18
  • 1
    `output_file` is only declared in the scope of the 1st `if` block now. So what's unclear about the compiler message? – πάντα ῥεῖ May 18 '23 at 11:18
  • you need to learn about a variables scope https://en.cppreference.com/w/cpp/language/scope. Frankly, this is fundamentals, explained in introductory books: https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list – 463035818_is_not_an_ai May 18 '23 at 11:19
  • What's preventing you from moving the for loop into the `if`'s body? – fabian May 18 '23 at 11:20
  • Also there are plethora of examples available, how to implement such configurable logging features in c++. You may start out looking at log4cpp or such open source stuff 1st. – πάντα ῥεῖ May 18 '23 at 11:22
  • for sophisticated logging with different log levels, different sinks, and compile time / runtime configurations you might want to use a logging library – 463035818_is_not_an_ai May 18 '23 at 11:22
  • 1
    See your C++ textbook for an explanation of how to use open() with streams. That's what you need to do. – Sam Varshavchik May 18 '23 at 11:24
  • 2
    If `printDebug` is known at compile time, you can use a macro instead and replace the `if`s with `#ifdef`s. Otherwise, you can put an `ofstream` in the main scope but only open it when `printDebug` is on. – interjay May 18 '23 at 11:24
  • The loop is intend to do other calculations in any case, but it supposed to print only if (printDebug==1). I thought that if printDebug was 1 in the first block ("if statement"), so the file "outputDelta.txt" would be already open. But if I understood you correctly, the code "forgets" if then the first scope is over? – Michael L. May 18 '23 at 11:27
  • 1
    Normally, I would try to get rid of this "special case", because it's not really good approach to solve a lot of code problems. If you want to use `output_file` in loop like you provided, you should create this variable outside of this `if` statement and just open file inside this `if` or you can move loop inside `if` statement as previous commenters stated. – Bolderaysky May 18 '23 at 11:36
  • 1
    On another note, adding logging to your code usually is NOT the best way of debugging your system. Logging should be used to observe WHAT is happening to the system (api entry/exit, credentials, session info) , for lower level correctness write unit tests. If you still run into bugs, write tests that reproduce them and then use a debugger to fix them. – Pepijn Kramer May 18 '23 at 11:48
  • Use a library like this one: https://github.com/gabime/spdlog – Aykhan Hagverdili May 18 '23 at 12:06

1 Answers1

1

You need to know how scopes work in C++. If you have a variable in one scope (between { }), this variable will be destroyed at the end of its scope.

void main()
{ // scope of function main()
    int x;

    { // new scope
        int y;
    } // y gets destroyed here

} // x gets destroyed here

The body of an if statement is a scope, too. Even if you don't have curly brackets but only a single statement like this:

if (true) // new scope
        int z;
// end of this scope

A variable can only be used in the scope it is declared in, or in any nested scope. This means I could still use x from the first code snippet in new scope where y is declared, but I can't access y from the outer scope.


When I understand your intention correct, you want something similar to this:

#include <fstream>  

#define DEBUG_LEVEL 1

int main() {

    #if DEBUG_LEVEL == 1
        std::ofstream output_file("outputDelta.txt"); // create output file
    #endif

    for (int i = 0; i < 1e2; i++) {
        #if DEBUG_LEVEL == 1
            output_file << i << "\n";
        #endif
    }

    return 0;
}

Note that the DEBUG_LEVEL now is not a variable but a macro. The preprocessor will check the conditions of your #ifs and either keep the code in between if they evaluate to true, or remove it if not. Therefore all the "removed" code won't be compiled. When you set DEBUG_LEVEL to something else, it would be as if you just had commented out the lines between each #if DEBUG_LEVEL == 1 and #endif.


As @Ayxan Haqverdili pointed out, writing all these #ifs and #endifs will polute your code and make it harder to read and understand.

If you want a better alternative, there are many loggers available online, but if you want to create your own, it's not that hard (to create a simple one).

I had something like this in a game of mine:

#if DEBUG_LEVEL == 1
#define DEBUG_LOG(msg) Log::Error(msg, __FILE__, __LINE__) // some logging function
#else
#define DEBUG_LOG(msg)
#endif

This is just a minimal example but I had something like this. Since the preprocessor will only define the DEBUG_LOG(msg) to be substituted by my logging function when DEBUG_LEVEL is 1, the logging function will only be called then, and if the DEBUG_LEVEL is 0, then it's going to do nothing at all.

Joel
  • 721
  • 1
  • 13
  • It would make sense to make the whole debugging thing a macro like `DEBUG_LOG(...)`, so it can disappear transparently, instead of sprinkling `#if` checks everywhere. – Aykhan Hagverdili May 18 '23 at 12:08