Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
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.
Functions.
Extra chars for my shortest answer.
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
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.
Related
I am developing a CAN-BUS logger with an ESP32. The data is written to a SDCard with fprintf.
I know I have to use fopen() to open the file and later fclose() to close the file again.
My question is how often should I open and close the file? Open it just one time and then maybe an hour later close it? Or open it, write 100 values, close it, open it again?
I don't want to lose a lot of data. The ESP32 will be on when the motorcycle with the CAN-BUS is running. And if the ignition is turned off then the ESP32 will have no power anymore. I don't mind if maybe data from the last 5 seconds is lost. But I don't want that i.e. 10 minutes of data is lost.
I also saw the fflush() function. Should I use that regularly i.e. every 10 seconds? And then maybe it's no problem if the file is never closed?
More info: I could design the device to make sure the power is on long enough so that fclose() is executed (no power failure before that). But I guess this is not really necessary if I don't mind that the last seconds of data is lost.
I put this question into StackOverflow and not electrical engineering because this is about writing the code for that project.
I searched and found similar questions here but I did not really find an answer to this question.
The Linux manpage for fflush includes a really important warning:
NOTES
Note that fflush() flushes only the user-space buffers provided by the C library. To ensure that the data is physically stored on disk the kernel buffers must be flushed too, for example, with sync(2) or fsync(2).
sync or fsync are part of the Posix interface, which might or might not be similar to the underlying file i/o interfaces on your ESP32. But the warning is probably still worth heeding.
The C standard has this wording for fflush, which makes it clear that all that is guaranteed is that fflush flushes out the buffers maintained by the C library, similar to the wording in the Linux manpage:
… the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file…
So if you want data to be actually committed to disk, fflush is not generally sufficient.
I made some tests to answer my question.
First I used this code:
ESP_LOGI(TAG, "Opening file");
FILE* f = fopen(fileName1, "a");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for append");
return;
}
int64_t t = 0;
for (unsigned long i = 1; i <= 10009000; i++)
{
t = esp_timer_get_time();
fprintf(f, "%010" PRId64, t);
fprintf(f, " ");
fprintf(f, "%10lu\n", i);
if (0 == i % 10000){
ESP_LOGI(TAG, "Flush file");
fflush(f);
}
}
//fclose(f);
ESP_LOGI(TAG, "File written");
Please notice that the file is never closed.
When I run that code on my ESP32 the file is created but nothing is written to the file. So at least with my configuration fclose() is necessary.
When I change the code to this:
for (unsigned long i = 1; i <= 109000; i++)
{
t = esp_timer_get_time();
fprintf(f, "%010" PRId64, t);
fprintf(f, " ");
fprintf(f, "%10lu\n", i);
if (0 == i % 10000){
//fflush(f);
ESP_LOGI(TAG, "Close and Open file");
fclose(f);
f = fopen(fileName1, "a");
}
}
//fclose(f);
ESP_LOGI(TAG, "File written");
then the data is written to the file. In this case the last line in the file is
0013521402 100000
So as expected the values after 100,000 (the last time when the file was closed) and before 109,000 (i <= 109000) are not written to the file.
My conclusion is: I have to use fclose(). The program does not write anything if I just use fflush() regularly. How often I have to close and open the file depends on how much data I am prepared to lose. For my application I will decide this later after some testing. Maybe I will close and open the file i.e. every 5 seconds. Or I will do this after writing 1000 lines or something like this.
This question already has answers here:
Why does printf not flush after the call unless a newline is in the format string?
(10 answers)
Closed 5 years ago.
I have the following snippet of code at the beginning of my program:
printf("Starting extraction of file %s \n", tarName);
// Open the tarFile
FILE* tarFile = fopen(tarName, "r");
if(tarFile == NULL) return EXIT_FAILURE;
// Read nFiles
printf("Reading header...");
...
When I execute it from the terminal I get the following output:
Starting extraction of file test.mytar
And then the program freezes, apparently never reaching the second printf.
test.mytar is an existing file in the same folder as my executable, and this is the same folder from where I am executing the terminal.
The file was created by me byte a byte, so it could possibly be violating file conventions I am not aware of.
What could possibly be going on here?
As pointed out in the comments, two things may happen.
a) the fopen fails (IO error, permission denied, missing file, ...). To know the exact cause, you need to print the errno (or GetLastError() on Windows) :
if(tarFile == NULL) {
printf("%s\n", strerror(errno));
return EXIT_FAILURE;
}
b) the fopen succeeds but printf("Reading header..."); does not show up anything because the message is buffered and not yet printed. To correct this, you can generally add a '\n' at the end of the message.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
Is there a preferable way to report errors in C? For example if a file that is supposed to be opened does not exist, should I use
if( fp == NULL )
{
perror("Error: ");
return(-1);
}
(copied from http://www.tutorialspoint.com/c_standard_library/c_function_perror.htm )
or
if( fp == NULL )
{
fprintf(stderr, "Unable to open file for reading.\n");
return(-1);
}
You can use perror() or strerror to get the error message. If you want to postpone the display of error message or if you want to log the message to a file, then save the errno and use strerror() because perror only writes to the standard error stream and it uses the global errno set and the errno might change any time if any library function is called before printing the error message.
Example using saved errno:
int savederrno;
....
if( fp == NULL )
{
savederrno = errno; /* Save the errno immediately after an api/lib function or a system call */
/*If you want to write to a log file now, write here using strerror and other library calls */
}
....
/* use strerror function to get the error message and write to log
or write to std error etc*/
The following man pages explain the error reporting in detail.
http://www.gnu.org/software/libc/manual/html_node/Error-Messages.html
http://man7.org/linux/man-pages/man3/errno.3.html
tutorialspoint.com is extremely terrible (at least when it comes to C) and as such must not be used. The standard resource to learn from is "The C Programming Language, 2nd edition" by Kernighan and Ritchie.
The preferred way to report stuff is to include the failing function in the message and use perror, e.g. perror("open")
EDIT: originally this did not include any justification for the claim about the site. I did not feel like it is necessary nor sensible. There is no write up I could link to either. They key was to avoid the site and everyone interested can easily conclude material in there is questionable at best and straight up wrong at worst.
However, since I got a weird backlash here are some excerpts:
http://www.tutorialspoint.com/c_standard_library/c_function_malloc.htm
#include <stdio.h>
#include <stdlib.h>
Missing include for strcpy and strcat.
int main()
{
char *str;
/* Initial memory allocation */
str = (char *) malloc(15);
No need to cast malloc. Missing null-check. Why the 15?
strcpy(str, "tutorialspoint");
Bad error-inducing style. What if the length was to change? If an explicit allocation really needs to happen, strlen() + 1 can be used to get the needed size.
printf("String = %s, Address = %u\n", str, str);
'u' is an incorrect specifier for pointer type.
/* Reallocating memory */
str = (char *) realloc(str, 25);
Standard bad idiom. The code should use a temporary pointer to recover from error, or if recovery is not an option, exit.
strcat(str, ".com");
What's up with realloc from 15 to 25 just to add ".com"?
printf("String = %s, Address = %u\n", str, str);
free(str);
return(0);
}
Does this justify my claim about the site?
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
What is the difference between running an already compiled C program with a.out file_name_here and a.out < file_name_here?
I remember something about Linux pipelines, but I cannot remember how to make the a.out file accept a file using the < symbol.
Basically what I am asking is this: how does the C code look for a C program that:
file_name_here is a text file with "hello world" as content
terminal gets "a.out < file_name_here" in command line
terminal shows output: "hello world"
a.out file_name_here passes "file_name_here" as an argument.
a.out < file_name_here is processed by the shell and presents the contents of "file_name_here" to the program on its "stdin".
Note that when you type a.out < filename, the shell handles the I/O redirection. The program is run with its standard input coming from the named file instead of from the terminal. When you type a.out filename, the program must deal with opening the file, reading it (and preferably closing it too). Neither of these examples uses a pipe. You could write cat file1 file2 file3 | a.out which would use a pipe and supply the contents of the three files as the standard input to the program.
Many programs on Unix systems are filters. If they are given file names to process, those are read. If they are given no file names, then they read standard input instead. An example of such a program is grep; other examples include cat and sort.
The general solution, in outline, is:
extern void process_file(FILE *fp); // Where the real work is done
int main(int argc, char **argv)
{
int rc = EXIT_SUCCESS;
if (argc == 1)
process_file(stdin);
else
{
for (int i = 1; i < argc; i++)
{
FILE *fp = fopen(argv[i], "r");
if (fp == 0)
{
fprintf(stderr, "%s: failed to open file %s for reading\n",
argv[0], argv[i]);
rc = EXIT_FAILURE;
}
else
{
process_file(fp);
fclose(fp);
}
}
}
return rc;
}
This will process any command line arguments as files to be read, resorting to reading standard input if no files are specified on the command line. There are legions of extra tweaks you can make to this outline. You can easily add option processing with getopt() (or getopt_long() if you're using GNU), and you can treat a file name of - as standard input if you wish. You can exit on failure to open a file if you think that's appropriate (sometimes it is; sometimes it isn't — grep doesn't, for example). You can pass the file name to the process_file() function. You can have the process_file() function report success failure, and track whether everything worked, exiting with zero only if all the operations were successful.
Just realized the problem I had. The < symbol means that the shell replaces normal user input in C with the content of the file, so all the normal calls such as fgets and sscanf work on it.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
This error occurred in my program:
Debug Assertion Failed!
Program:C:\JM\.\bin\ldecod.exe
File: f:\ff\vctools\crt_bld\self_x86\crt\src\fscanf.c
Line:52
Expression: (stream!=NULL)
For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.
(Press Retry to debug the application.)
What seems to be the problem here?
CODE
This is the portion of my code where I used fscanf. When mi=297 it worked perfectly fine.
int myframe[29699];
........
if (CONCEAL==1)
{
FILE*concealfile;
concealfile=fopen("myerrsim%15carphone.txt","r");
for(mi=0; mi<14850; mi++)
{
fscanf(concealfile,"%d\n", &myframe[mi]);
}
if (myctr==currMB->mbAddrX+(((currMB)->p_Slice)->p_Img)->number*99 && currMB->mbAddrX+(((currMB)->p_Slice)->p_Img)->number>0)
{
if (myframe[myctr]==1)
{
mbmode=0;
}
myctr++;
}
}
Additional questions! I am encountering several similar errors. The
programs breaks at different portions of source codes and some of
which are built in functions like "fscanf". I do not know the reason.
And sometimes a program on my computer, like "Flash Player" notifies
me of some sort of error. Is this because the pointers used in my
program are trying to access "Flash Player"? Why is this happening and
what is the possible fix?
What are assertion errors simply put?
For #Jonathan Leffler
#ifdef _DEBUG
/*
* Report error.
*
* If _CRT_ERROR has _CRTDBG_REPORT_WNDW on, and user chooses
* "Retry", call the debugger.
*
* Otherwise, continue execution.
*
*/
if (rterrnum != _RT_CRNL && rterrnum != _RT_BANNER && rterrnum != _RT_CRT_NOTINIT)
{
switch (_CrtDbgReportW(_CRT_ERROR, NULL, 0, NULL, L"%s", error_text))
{
-> case 1: _CrtDbgBreak(); msgshown = 1; break;
case 0: msgshown = 1; break;
}
}
where -> is the unexpected breakpoint.
located in C:\Program Files\Microsoft Visual Studio 11.0\VC\crt\src\crt0msg.c
It appears you did something like:
char name[64];
FILE *fp = fopen("c:/non-existent/file", "r");
fscanf(fp, "%s", name);
without checking that fopen() was successful, and fprintf() triggered an assertion failure. When fopen() fails, it returns a NULL pointer, and the assertion says stream != NULL (where 'stream' is a file stream, the first argument to fscanf(), and means aFILE *such asfp`).
There's an outside chance that you use fscanf_s() because you're on Windows — it's the same basic story, but fscanf_s() checks for such problems where fscanf() does not.
Possible fix:
char name[64];
FILE *fp = fopen("c:/non-existent/file", "r");
if (fp == 0)
...report failure to open file (and exit or return)...
if (fscanf(fp, "%s", name) != 1)
...report read failure...