-4

I'm putting some very temporary debug prints into various userspace programs to figure out what code runs on an embedded Linux device, and I want these prints to write to a file without leaving it open. To make the debug more portable between the various programs, it would be nice to have a one-liner that can open a file, write to it, and close it without having to define a function/macro elsewhere. I could do something like:

{ FILE *f = fopen("filename", "a"); if (f) { fprintf(f, "DEBUG MSG\n"); fclose(f); } else printf("File open error!\n"); }

which is just removing the whitespace from:

{
    FILE *f = fopen("filename", "a");
    if (f) {
        fprintf(f, "DEBUG MSG\n");
        fclose(f);
    }
    else
        printf("File open error!\n");
}

But this feels needlessly complex. Is there some more simplified way of doing this? Again, I'm not talking about making it a function, as I'd like it to be copy/pasted between separate programs without defining a function every time. It's just basically a temporary printk equivalent for userspace.

vestlen
  • 1,103
  • 11
  • 17
  • 12
    Usually those one-liners are called functions... – squiguy Apr 20 '16 at 21:37
  • One-line as in 'in the source code'? Best make it a macro, so you can easily disable it later on. – Jongware Apr 20 '16 at 21:38
  • Sure: Put the logging stuff into a seperate module, call the "open" function of that module early from `main`, the `close` just before you end your program and the `log` function wherever you want to write to the log file. – too honest for this site Apr 20 '16 at 21:38
  • Any particular reason that code in not using something like a function called `debug_printf(int, ...)`? – chux - Reinstate Monica Apr 20 '16 at 21:45
  • 1
    Added clarification to the question. I'm not really looking for a "make it a function" solution because I want something simple to paste into multiple programs, similar to using printk's. Just looking for anything I may have missed in my block that could simplify it. – vestlen Apr 20 '16 at 21:47
  • In the case where `fopen` fails, you should be writing your error message to `stderr`, not `stdout`. – Tom Karzes Apr 20 '16 at 21:55
  • @MarkPlotnick YES! Of course! That is exactly what I was looking for. You can make this into an answer if you'd like. – vestlen Apr 20 '16 at 22:00
  • 1
    Why do you want to reduce things to one line? Do you *really* believe your brain can comprehend that many things going on at once? Or do you endeavor to produce code you can't understand? – Andrew Henle Apr 20 '16 at 22:36
  • 1
    I'm voting to close this, because it's a Code Golf type question. *Here's my really bad idea that works. Can anybody make it shorter?* is a challenge, not an actual problem you're facing. There's an entire site here at [se] for those sorts of question. – Ken White Apr 20 '16 at 22:48

3 Answers3

5

Functions.


Extra chars for my shortest answer.

Dimitar
  • 4,402
  • 4
  • 31
  • 47
1

Potential problem with fprintf(f, "DEBUG MSG\n");

I assume "DEBUG MSG\n" is some placeholder for the true message. Should the true message contain a '%', then the function will look for missing arguments. Use fputs() - its can be lighter on the CPU too than fprintf().

fputs(debug_message, f);

The true message may lack a '\n' and then get stuck in buffering just prior to a program crash. Best to flush when you are done.

fputs(debug_message, f);
fflush(f);

Pedantic: Debugging is for problem solving. Too often the message itself is questionable/corrupt. Consider using protection. (I do not trust excessive long debug messages). Of course the more junk in the fprintf(), the greater the performance impact of debug logging.

if (f) {
  if (debug_message) {
    fprintf(f, "%.99s", debug_message);
    fflush(f);
    fclose(f);
  }
}

As mentioned by @Tom Karzes, send diagnostic message to stderr, rather than stdout.


Overall, I would use a function call wrapped in a conditional macro rather than embedded code. YMMV.

#ifdef NDEBUG
  #define DEBUG_PUTS(level, s)
#else
  #define DEBUG_PUTS(level, s) debug_puts((level), __FILE__, __LINE__, (s))
#endif
Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

As mentioned by Mark Plotnick, a workaround for Linux systems is:

system("echo DEBUG MSG >> filename");

It's not pretty but it's quick, copy/pasteable, and easy to use for this situation because it can also write to /dev/kmsg:

system("echo DEBUG MSG >> /dev/kmsg");

which allows it to behave like a printk. Of course, it's not a safe solution and can't be used with any chars that interfere with a bash echo, but for a temporary static debug message it works fine.

vestlen
  • 1,103
  • 11
  • 17
  • 1
    Note: This is an OS specific solution. The post did not specify the OS and had "runs on an embedded device" which implies there might not even be an underlying OS. – chux - Reinstate Monica Apr 21 '16 at 19:06
  • Good point. I added this to the question. I was hoping for a more general solution (like a library function that I had been unaware of or something) but this one solved the problem for my situation. – vestlen Apr 22 '16 at 01:58