0

Suppose we have application on Linux, pure C. Application consists of several functions - f1, f2 and f3, which receive a structure. One element of the structure is debug_mode, with values ON or OFF.

How can I switch debug mode in f1, f2 and f3 (for example, some printfs) when the structure has debug_mode == ON?

Should I always use if statements to check debug_mode for every incoming structure or there is some another best practise to not use always if statements?

For example, these could be traces in telecom products, where we could collect some trace data for a specified subscriber.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 1
    If you want to check if a particular variable at run time has a given value, you use an `if` statement. – dbush Feb 12 '18 at 14:47
  • 1
    We have no way of knowing what you are talking about. This "debug mode" is your application specific feature. – Eugene Sh. Feb 12 '18 at 14:48
  • I would suggest using a logging libary or special logging functions instead of `if (..) printf` – mbieren Feb 12 '18 at 15:15
  • 2
    Consider [C `#define` macro for debug printing](https://stackoverflow.com/questions/1644868/c-define-macro-for-debug-printing). The code outlined there supports 'debug levels', and associates printing with debug levels. For larger programs, I use the 'multiple subsystem' code alluded to, with the ability to have different debug levels for separate subsystems at run time. You can control whether debug is included at all; you can also control how much debug output is generated at runtime. – Jonathan Leffler Feb 12 '18 at 15:38
  • He wants to change it during runtime. Macros do not help here. A solution would be a global variable. This variable is altered by a signal handler and queried via `if (GLOBAL_DEBUG) printf` – mbieren Feb 12 '18 at 15:41
  • 1
    And if you're curious, you can look at my code in GitHub in my [SOQ](https://github.com/jleffler/soq) (Stack Overflow Questions) repository as files `debug.c`, `debug.h` and `mddebug.c` in the [src/libsoq](https://github.com/jleffler/soq/tree/master/src/libsoq) sub-directory. – Jonathan Leffler Feb 12 '18 at 16:05
  • Your question is unclear and too broad. You don't tell enough about your application! You should provide some [MCVE]. Please **edit your question** to improve it a lot! – Basile Starynkevitch Feb 12 '18 at 19:16

2 Answers2

1

You can change it during runtime like this :

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

#define FALSE 0 
#define TRUE 1

volatile sig_atomic_t GLOBAL_DEBUG = FALSE;

void sig_handler(int signo)
{
    if (signo == SIGUSR1) {
        // printf("received SIGUSR1\n");
        GLOBAL_DEBUG = TRUE;
    } else if (signo == SIGUSR2) {
        GLOBAL_DEBUG = FALSE;
        // printf("received SIGUSR2\n");
    }
}

int main (int argc, char **argv) {

    if (signal(SIGUSR1, sig_handler) == SIG_ERR)
        printf("\ncan't catch SIGUSR1\n");

    if (signal(SIGUSR2, sig_handler) == SIG_ERR)
        printf("\ncan't catch SIGUSR2\n");

    while (TRUE) {
        if (GLOBAL_DEBUG) printf ("DEBUG == TRUE\n");
        printf ("Hello world\n");
        sleep(1);
    }
}

And the switch GLOBAL_DEBUG during runtime like this :

user@host:~ $ kill -SIGUSR2 <pid of program>
user@host:~ $ kill -SIGUSR1 <pid of program>

BTW, read signal-safety(7) (explaining why printf should be avoided inside signal handlers) and signal(7). sig_atomic_t is specified in the C11 standard (see n1570).

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
mbieren
  • 1,034
  • 8
  • 31
  • 1
    Using `printf` (which is not an *async-signal-safe* function) inside a signal handler is **against the rules** of [signal-safety(7)](http://man7.org/linux/man-pages/man7/signal-safety.7.html) and [signal(7)](http://man7.org/linux/man-pages/man7/signal.7.html). So it is *undefined behavior*; without these `printf ` the answer is interesting, so please edit your answer to remove these offending `printf`-s inside your `sig_handler` – Basile Starynkevitch Feb 12 '18 at 19:01
  • 1
    Also `GLOBAL_DEBUG` should be declared `volatile sig_atomic_t GLOBAL_DEBUG;` not `int GLOBAL_DEBUG;` – Basile Starynkevitch Feb 12 '18 at 19:07
  • This is just a demo. – mbieren Feb 12 '18 at 21:57
  • 1
    So I edited your answer to improve it. The original was wrong – Basile Starynkevitch Feb 13 '18 at 05:46
1

You could use signals (see signal(7) & signal-safety(7)), as explained in mbieren's answer. Of course you cannot call printf (or any non async-signal-safe function) from a signal handler, and the flag should be declared as volatile sig_atomic_t GLOBAL_DEBUG;

You could design your program otherwise. Perhaps your program has already some event loop (e.g. because it is a GUI application). Then you could add some RPCJSON service (or some HTTP one, or your own socket(7) or unix(7) based protocol, probably some text-based one) to your program. You'll find many libraries to help you (for example, libonion enables you to add some HTTP service to your program; so you might change the debug flag via your web server!).

You don't tell enough about your program to get more precise help.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547