Print to error stream c

Print to stderr in C This article will introduce multiple methods about how to print to stderr in C. Use the fprintf Function to Print to stderr in C The standard I/O library in C provides three text streams that are opened implicitly when the program is started on the system. These streams are, […]

Содержание

  1. Print to stderr in C
  2. Use the fprintf Function to Print to stderr in C
  3. Use the dprintf Function to Print to stderr in C
  4. Use the fwrite Function to Print to stderr in C
  5. Error checking fprintf when printing to stderr
  6. 5 Answers 5
  7. Why use stderr when printf works fine?
  8. 5 Answers 5
  9. Is it possible to trap errors from C printf()?
  10. 4 Answers 4
  11. Is it possible to trap errors from C printf()?
  12. 4 Answers 4

Print to stderr in C

This article will introduce multiple methods about how to print to stderr in C.

Use the fprintf Function to Print to stderr in C

The standard I/O library in C provides three text streams that are opened implicitly when the program is started on the system. These streams are,

  • standard input ( stdin ) — used for reading input.
  • standard output ( stdout ) — used for writing output.
  • standard error stream ( stderr ) — used to log error or debug messages during run-time.

In order to print data to these streams, printf family functions are utilized. fprintf is usually employed to output text to a specific output stream. When we need to print to stderr , we are targeting the stderr stream and passing it as the first argument to the function. The second argument is the format string itself, which provides means to include different objects into the output and construct the given formatting. Note that we include multiple strings in «» as they will automatically be concatenated during the compilation.

Use the dprintf Function to Print to stderr in C

Alternatively, we can use the dprintf function, which is similar to the fprintf call, except that it takes the file descriptor as the first argument. File descriptors in Unix based systems are integer values associated with the open files of the program.

Note that, standard Unix header — includes macro definitions for these three mentioned streams as — STDIN_FILENO , STDOUT_FILENO and STDERR_FILENO . We define two macros as well — RED and NC , which are just ASCII character sequences to modify text color in the output.

Use the fwrite Function to Print to stderr in C

Another alternative to the previous functions is fwrite . It is mostly used for binary stream I/O, but we can still call it to print text to output streams. fwrite takes four arguments, and the first of them is the pointer to the string that needs to be printed. The next two parameters specify the size of the number of data items stored at the pointer and the size of each of them. Since we print a single string, the third argument can be 1 , and the size corresponds to the length of the string. The fourth parameter is the FILE* pointing to the desired stream.

Источник

Error checking fprintf when printing to stderr

According to the docs, fprintf can fail and will return a negative number on failure. There are clearly many situations where it would be useful to check this value.

However, I usually use fprintf to print error messages to stderr. My code will usually look something like this:

In these cases, is it still possible for fprintf to fail? If so, is there anything that can be done to display the error message somehow or is there is a more reliable alternative to fprintf?

If not, is there any need to check fprintf when it is used in this way?

5 Answers 5

The C standard says that the file streams stdin , stdout , and stderr shall be connected somewhere, but they don’t specify where, of course. (C11 §7.21.3 Files ¶7:

At program startup, three text streams are predefined and need not be opened explicitly — standard input (for reading conventional input), standard output (for writing conventional output), and standard error (for writing diagnostic output). As initially opened, the standard error stream is not fully buffered; the standard input and standard output streams are fully buffered if and only if the stream can be determined not to refer to an interactive device.

It is perfectly feasible to run a program with the standard streams redirected:

Your writes will succeed — but the information won’t go anywhere. A more brutal way of running your program is:

This time, it has been run without open file streams for stdout and stderr — in contravention of the the standard. It is still reading from /dev/null in the example, which means it doesn’t get any useful data input from stdin .

Many a program doesn’t bother to check that the standard I/O channels are open. Many a program doesn’t bother to check that the error message was successfully written. Devising a suitable fallback as outline by Tim Post and whitey04 isn’t always worth the effort. If you run the ls command with its outputs suppressed, it will simply do what it can and exits with a non-zero status:

(Tested RHEL Linux.) There really isn’t a need for it to do more. On the other hand, if your program is supposed to run in the background and write to a log file, it probably won’t write much to stderr , unless it fails to open the log file (or spots an error on the log file).

Note that if you fall back on syslog(3) (or POSIX), you have no way of knowing whether your calls were ‘successful’ or not; the syslog functions all return no status information. You just have to assume that they were successful. It is your last resort, therefore.

Источник

Why use stderr when printf works fine?

Why should we use stderr when printing a custom error message from printf works fine?

For example why use stderr at all when I can just write a statement like this:

5 Answers 5

It is good practice to redirect all error messages to stderr , while directing regular output to stdout . It is beneficial to do this because anything written to stderr is not buffered, i.e., it is immediately written to the screen so that the user can be warned immediately.

stderr stands for standard error stream.

In console programming, it is the console — the screen. It is essentially the same as stdout .

The general practice is to redirect all error messages to stderr and all regular output to stdout .

The reason is that it is possible to redirect standard output to a file instead of the screen. So If you perform a dir > dirlist.txt command on the command prompt, the directory listing goes into the text file instead of the screen. If you code to redirect error messages to stderr , the errors will always go to the screen instead of the file so that the user could be warned immediately instead of ending up seeing unexpected results in the file.

Using printf() will display the error message to the console, which will be stored in the stdout buffer, but using stderr , is different.

stderr can be used as an argument for any function that takes an argument of type FILE* expecting an output stream, like fputs or fprintf .

Although in many cases, both stdout and stderr are associated with the same output device (like the console), applications may differentiate between what is sent to stdout vs stderr for situations when one of them is redirected. For example, it is a common practice to redirect the regular output of a console program ( stdout ) to a file, while expecting the error messages to keep appearing in the console.

It is also possible to redirect stderr to another destination from within a program using the freopen function.

Also, stderr is never fully buffered on startup. It is library-dependent whether the stream is line-buffered or not-buffered by default (see setvbuf ).

Источник

Is it possible to trap errors from C printf()?

I have a C++ program for which validated API users (not interactive users, so there is no major security/integrity exposure here) can pass a parameter that becomes a format string for printf() (actually, for vsnprintf()). Of course, bad format specifiers make the program blow up. I have documented that and it is acceptable — but is there any way to trap printf() errors rather than having the C runtime assert?

Environment is pretty much standard Posix (z/OS XLC, FWIW).

4 Answers 4

Call sigsetjmp() prior to using the potentially bad format, and install a custom handler for SIGSEGV and SIGBUS that calls siglongjmp() with the context from the sigsetjmp() call.

Just be sure to use restore the signal handlers after you don’t need them lest a SIGSEGV somewhere else cause some unexpected results.

The format library provides a class for formatting arguments according to a format-string, as does printf, but with two major differences :

format sends the arguments to an internal stream, and so is entirely type-safe and naturally supports all user-defined types.

You can use C++ exception with this library.

I was tempted to recommend a simple C++ style try/catch:

But I figure you tried that and have a reason why it doesn’t meet your needs.

The deeper alternative is an LE Condition Handler — it’s essentially a callback routine that gives you control any time an exception occurs, and it includes a way to resume execution after an error. Read more by Googling CEEHDLR or see the «Handling error conditions, exceptions, and signals» section of the XL C/C++ Programming Guide.

In a pinch, you can also wrap your calls to printf() with ESTAE/ESPIE macros to trap the error before the runtime sees it. yes, it takes a few lines of assembler, but many times it’s possible to get way more granular this way.

Источник

Is it possible to trap errors from C printf()?

I have a C++ program for which validated API users (not interactive users, so there is no major security/integrity exposure here) can pass a parameter that becomes a format string for printf() (actually, for vsnprintf()). Of course, bad format specifiers make the program blow up. I have documented that and it is acceptable — but is there any way to trap printf() errors rather than having the C runtime assert?

Environment is pretty much standard Posix (z/OS XLC, FWIW).

4 Answers 4

Call sigsetjmp() prior to using the potentially bad format, and install a custom handler for SIGSEGV and SIGBUS that calls siglongjmp() with the context from the sigsetjmp() call.

Just be sure to use restore the signal handlers after you don’t need them lest a SIGSEGV somewhere else cause some unexpected results.

The format library provides a class for formatting arguments according to a format-string, as does printf, but with two major differences :

format sends the arguments to an internal stream, and so is entirely type-safe and naturally supports all user-defined types.

You can use C++ exception with this library.

I was tempted to recommend a simple C++ style try/catch:

But I figure you tried that and have a reason why it doesn’t meet your needs.

The deeper alternative is an LE Condition Handler — it’s essentially a callback routine that gives you control any time an exception occurs, and it includes a way to resume execution after an error. Read more by Googling CEEHDLR or see the «Handling error conditions, exceptions, and signals» section of the XL C/C++ Programming Guide.

In a pinch, you can also wrap your calls to printf() with ESTAE/ESPIE macros to trap the error before the runtime sees it. yes, it takes a few lines of assembler, but many times it’s possible to get way more granular this way.

Источник

  1. Use the fprintf Function to Print to stderr in C
  2. Use the dprintf Function to Print to stderr in C
  3. Use the fwrite Function to Print to stderr in C

Print to stderr in C

This article will introduce multiple methods about how to print to stderr in C.

Use the fprintf Function to Print to stderr in C

The standard I/O library in C provides three text streams that are opened implicitly when the program is started on the system. These streams are,

  • standard input (stdin) — used for reading input.
  • standard output (stdout) — used for writing output.
  • standard error stream (stderr) — used to log error or debug messages during run-time.

In order to print data to these streams, printf family functions are utilized. fprintf is usually employed to output text to a specific output stream. When we need to print to stderr, we are targeting the stderr stream and passing it as the first argument to the function. The second argument is the format string itself, which provides means to include different objects into the output and construct the given formatting. Note that we include multiple strings in "" as they will automatically be concatenated during the compilation.

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>

#define RED "e[0;31m"
#define NC "e[0m"

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

    if (argc != 2) {
        fprintf(stderr, RED "[ERROR]"
               NC  ": No string argument provided! n"
                   "You must provide a program path as argumentn");
        exit(EXIT_FAILURE);
    }

    char *str = malloc(strlen(argv[1]) + 1);
    strcpy(str, argv[1]);

    printf("str: %sn", str);

    free(str);
    exit(EXIT_SUCCESS);
}

Output:

[ERROR]: No string argument provided!
You must provide a program path as argument

Use the dprintf Function to Print to stderr in C

Alternatively, we can use the dprintf function, which is similar to the fprintf call, except that it takes the file descriptor as the first argument. File descriptors in Unix based systems are integer values associated with the open files of the program.

Note that, standard Unix header — <unistd.h> includes macro definitions for these three mentioned streams as — STDIN_FILENO, STDOUT_FILENO and STDERR_FILENO. We define two macros as well — RED and NC, which are just ASCII character sequences to modify text color in the output.

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>

#define RED "e[0;31m"
#define NC "e[0m"

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

    if (argc != 2) {
        dprintf(STDERR_FILENO, RED "[ERROR]"
                        NC  ": No string argument provided! n"
                        "You must provide a program path as argumentn");
        exit(EXIT_FAILURE);
    }

    char *str = malloc(strlen(argv[1]) + 1);
    strcpy(str, argv[1]);

    printf("str: %sn", str);

    free(str);
    exit(EXIT_SUCCESS);
}

Output:

[ERROR]: No string argument provided!
You must provide a program path as argument

Use the fwrite Function to Print to stderr in C

Another alternative to the previous functions is fwrite. It is mostly used for binary stream I/O, but we can still call it to print text to output streams. fwrite takes four arguments, and the first of them is the pointer to the string that needs to be printed. The next two parameters specify the size of the number of data items stored at the pointer and the size of each of them. Since we print a single string, the third argument can be 1, and the size corresponds to the length of the string. The fourth parameter is the FILE* pointing to the desired stream.

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>

#define RED "e[0;31m"
#define NC "e[0m"


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

    if (argc != 2) {
        fwrite("[ERROR] : No string argument provided!n", 39, 1, stderr);
        exit(EXIT_FAILURE);
    }

    char *str = malloc(strlen(argv[1]) + 1);
    strcpy(str, argv[1]);

    printf("str: %sn", str);

    free(str);
    exit(EXIT_SUCCESS);
}

Output:

[ERROR] : No string argument provided!

Введение

Ошибки, увы, неизбежны, поэтому их обработка занимает очень важное место в программировании. И если алгоритмические ошибки можно выявить и исправить во время написания и тестирования программы, то ошибок времени выполнения избежать нельзя в принципе. Сегодня мы рассмотрим функции стандартной библиотеки (C Standard Library) и POSIX, используемые в обработке ошибок.

Переменная errno и коды ошибок

<errno.h>

errno – переменная, хранящая целочисленный код последней ошибки. В каждом потоке существует своя локальная версия errno, чем и обусловливается её безопасность в многопоточной среде. Обычно errno реализуется в виде макроса, разворачивающегося в вызов функции, возвращающей указатель на целочисленный буфер. При запуске программы значение errno равно нулю.

Все коды ошибок имеют положительные значения, и могут использоваться в директивах препроцессора #if. В целях удобства и переносимости заголовочный файл <errno.h> определяет макросы, соответствующие кодам ошибок.

Стандарт ISO C определяет следующие коды:

  • EDOM – (Error domain) ошибка области определения.
  • EILSEQ – (Error invalid sequence) ошибочная последовательность байтов.
  • ERANGE – (Error range) результат слишком велик.

Прочие коды ошибок (несколько десятков) и их описания определены в стандарте POSIX. Кроме того, в спецификациях стандартных функций обычно указываются используемые ими коды ошибок и их описания.

Нехитрый скрипт печатает в консоль коды ошибок, их символические имена и описания:

#!/usr/bin/perl

use strict;
use warnings;

use Errno;

foreach my $err (sort keys (%!)) {
    $! = eval "Errno::$err";
    printf "%20s %4d   %sn", $err, $! + 0, $!
}

Если вызов функции завершился ошибкой, то она устанавливает переменную errno в ненулевое значение. Если же вызов прошёл успешно, функция обычно не проверяет и не меняет переменную errno. Поэтому перед вызовом функции её нужно установить в 0.

Пример:

/* convert from UTF16 to UTF8 */
errno = 0;	
n_ret = iconv(icd, (char **) &p_src, &n_src, &p_dst, &n_dst);   
	
if (n_ret == (size_t) -1) {
    VJ_PERROR();
    if (errno == E2BIG)  
        fprintf(stderr, " Error : input conversion stopped due to lack of space in the output buffern");
    else if (errno == EILSEQ)  
        fprintf(stderr, " Error : input conversion stopped due to an input byte that does not belong to the input codesetn");
    else if (errno == EINVAL)  
        fprintf(stderr, " Error : input conversion stopped due to an incomplete character or shift sequence at the end of the input buffern");
/* clean the memory */   
    free(p_out_buf);
    errno = 0;
    n_ret = iconv_close(icd);      
    if (n_ret == (size_t) -1)  
        VJ_PERROR();
    return (size_t) -1; 
}

Как видите, описания ошибок в спецификации функции iconv() более информативны, чем в <errno.h>.

Функции работы с errno

Получив код ошибки, хочется сразу получить по нему её описание. К счастью, ISO C предлагает целый набор полезных функций.

<stdio.h>

void perror(const char *s);

Печатает в stderr содержимое строки s, за которой следует двоеточие, пробел и сообщение об ошибке. После чего печатает символ новой строки 'n'.

Пример:

/*
//  main.c
//  perror example
//
//  Created by Ariel Feinerman on 23/03/17.
//  Copyright  2017 Feinerman Research, Inc. All rights reserved.
*/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main(int argc, const char * argv[]) 
{
    // Generate unique filename.
    char *file_name = tmpnam((char[L_tmpnam]){0});
   
    errno = 0;
    FILE *file = fopen(file_name, "rb");

    if (file) {
        // Do something useful. 
        fclose(file);
    }
    else {
        perror("fopen() ");
    }
	
    return EXIT_SUCCESS;
}

<string.h>

char* strerror(int errnum);
Возвращает строку, содержащую описание ошибки errnum. Язык сообщения зависит от локали (немецкий, иврит и даже японский), но обычно поддерживается лишь английский.

/*
//  main.c
//  strerror example
//
//  Created by Ariel Feinerman on 23/03/17.
//  Copyright  2017 Feinerman Research, Inc. All rights reserved.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <errno.h>

int main(int argc, const char * argv[]) 
{
    // Generate unique filename.
    char *file_name = tmpnam((char[L_tmpnam]){0});

    errno = 0;
    FILE *file = fopen(file_name, "rb");
    // Save error number. 
    errno_t error_num = errno;
	
    if (file) {
        // Do something useful. 
        fclose(file);
    }
    else {
        char *errorbuf = strerror(error_num);
        fprintf(stderr, "Error message : %sn", errorbuf);
    }
    
    return EXIT_SUCCESS;
}

strerror() не безопасная функция. Во-первых, возвращаемая ею строка не является константной. При этом она может храниться в статической или в динамической памяти в зависимости от реализации. В первом случае её изменение приведёт к ошибке времени выполнения. Во-вторых, если вы решите сохранить указатель на строку, и после вызовите функцию с новым кодом, все прежние указатели будут указывать уже на новую строку, ибо она использует один буфер для всех строк. В-третьих, её поведение в многопоточной среде не определено в стандарте. Впрочем, в QNX она объявлена как thread safe.

Поэтому в новом стандарте ISO C11 были предложены две очень полезные функции.

size_t strerrorlen_s(errno_t errnum);

Возвращает длину строки с описанием ошибки errnum.

errno_t strerror_s(char *buf, rsize_t buflen, errno_t errnum);

Копирует строку с описание ошибки errnum в буфер buf длиной buflen.

Пример:

/*
//  main.c
//  strerror_s example 
//
//  Created by Ariel Feinerman on 23/02/17.
//  Copyright  2017 Feinerman Research, Inc. All rights reserved.
*/

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <errno.h>

int main(int argc, const char * argv[]) 
{
    // Generate unique filename.
    char *file_name = tmpnam((char[L_tmpnam]){0});
	
    errno = 0;
    FILE *file = fopen(file_name, "rb");
    // Save error number. 
    errno_t error_num = errno;

    if (file) {
        // Do something useful. 
        fclose(file);
    }
    else {
#ifdef __STDC_LIB_EXT1__
    size_t error_len = strerrorlen_s(errno) + 1;
    char error_buf[error_len];
    strerror_s(error_buf, error_len, errno);
    fprintf(stderr, "Error message : %sn", error_buf);
#endif
    }
	
    return EXIT_SUCCESS;
}

Функции входят в Annex K (Bounds-checking interfaces), вызвавший много споров. Он не обязателен к выполнению и целиком не реализован ни в одной из свободных библиотек. Open Watcom C/C++ (Windows), Slibc (GNU libc) и Safe C Library (POSIX), в последней, к сожалению, именно эти две функции не реализованы. Тем не менее, их можно найти в коммерческих средах разработки и системах реального времени, Embarcadero RAD Studio, INtime RTOS, QNX.

Стандарт POSIX.1-2008 определяет следующие функции:

char *strerror_l(int errnum, locale_t locale);

Возвращает строку, содержащую локализованное описание ошибки errnum, используя locale. Безопасна в многопоточной среде. Не реализована в Mac OS X, FreeBSD, NetBSD, OpenBSD, Solaris и прочих коммерческих UNIX. Реализована в Linux, MINIX 3 и Illumos (OpenSolaris).

Пример:

/*
 //  main.c
 //  strerror_l example – works on Linux, MINIX 3, Illumos
 //
 //  Created by Ariel Feinerman on 23/03/17.
 //  Copyright  2017 Feinerman Research, Inc. All rights reserved.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <errno.h>

#include <locale.h>

int main(int argc, const char * argv[]) 
{
    locale_t locale = newlocale(LC_ALL_MASK, "fr_FR.UTF-8", (locale_t) 0);
    
    if (!locale) {
        fprintf(stderr, "Error: cannot create locale.");
        exit(EXIT_FAILURE);
    }

    // Generate unique filename.
    char *file_name = tmpnam((char[L_tmpnam]){0});
	
    errno = 0;
    FILE *file = fopen(tmpnam(file_name, "rb");
    // Save error number. 
    errno_t error_num = errno;

    if (file) {
        // Do something useful. 
        fclose(file);
    }
    else {
        char *error_buf = strerror_l(errno, locale);
        fprintf(stderr, "Error message : %sn", error_buf);
    }
	
    freelocale(locale);
	
    return EXIT_SUCCESS;
}

Вывод:

Error message : Aucun fichier ou dossier de ce type

int strerror_r(int errnum, char *buf, size_t buflen);

Копирует строку с описание ошибки errnum в буфер buf длиной buflen. Если buflen меньше длины строки, лишнее обрезается. Безопасна в многоготочной среде. Реализована во всех UNIX.

Пример:

/*
//  main.c
//  strerror_r POSIX example
//
//  Created by Ariel Feinerman on 25/02/17.
//  Copyright  2017 Feinerman Research, Inc. All rights reserved.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <errno.h>

#define MSG_LEN 1024 

int main(int argc, const char * argv[]) 
{
    // Generate unique filename.
    char *file_name = tmpnam((char[L_tmpnam]){0});
    
    errno = 0;
    FILE *file = fopen(file_name, "rb");
    // Save error number. 
    errno_t error_num = errno;	
	
    if (file) {
        // Do something useful.
        fclose(file);
    }
    else {
        char error_buf[MSG_LEN];
        errno_t error = strerror_r (error_num, error_buf, MSG_LEN);
		
        switch (error) {
            case EINVAL:
                    fprintf (stderr, "strerror_r() failed: invalid error code, %dn", error);
                    break;
            case ERANGE:
                    fprintf (stderr, "strerror_r() failed: buffer too small: %dn", MSG_LEN);
            case 0:
                    fprintf(stderr, "Error message : %sn", error_buf);
                    break;
            default: 
                    fprintf (stderr, "strerror_r() failed: unknown error, %dn", error);
                    break;
        }
    }
    
    return EXIT_SUCCESS;
}

Увы, никакого аналога strerrorlen_s() в POSIX не определили, поэтому длину строки можно выяснить лишь экспериментальным путём. Обычно 300 символов хватает за глаза. GNU C Library в реализации strerror() использует буфер длиной в 1024 символа. Но мало ли, а вдруг?

Пример:

/*
 //  main.c
 //  strerror_r safe POSIX example
 //
 //  Created by Ariel Feinerman on 23/03/17.
 //  Copyright  2017 Feinerman Research, Inc. All rights reserved.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <errno.h>

#define MSG_LEN 1024 
#define MUL_FACTOR 2

int main(int argc, const char * argv[]) 
{
    // Generate unique filename.
    char *file_name = tmpnam((char[L_tmpnam]){0});
	
    errno = 0;
    FILE *file = fopen(file_name, "rb");
    // Save error number. 
    errno_t error_num = errno;
	
    if (file) {
        // Do something useful.
        fclose(file);
    }
    else {
        errno_t error = 0;
        size_t error_len = MSG_LEN; 
		
        do {
            char error_buf[error_len];
            error = strerror_r (error_num, error_buf, error_len);
            switch (error) {
                    case 0:
                            fprintf(stderr, "File : %snLine : %dnCurrent function : %s()nFailed function : %s()nError message : %sn", __FILE__, __LINE__, __func__, "fopen", error_buf);
	                    break;
                    case ERANGE: 
                            error_len *= MUL_FACTOR;
                            break;
                    case EINVAL: 
                            fprintf (stderr, "strerror_r() failed: invalid error code, %dn", error_num);
                            break;
                    default:
                            fprintf (stderr, "strerror_r() failed: unknown error, %dn", error);
                            break;
            }
			
        } while (error == ERANGE);
    }
    
    return EXIT_SUCCESS;
}

Вывод:

File : /Users/ariel/main.c
Line : 47
Current function : main()
Failed function : fopen()
Error message : No such file or directory

Макрос assert()

<assert.h>

void assert(expression)

Макрос, проверяющий условие expression (его результат должен быть числом) во время выполнения. Если условие не выполняется (expression равно нулю), он печатает в stderr значения __FILE__, __LINE__, __func__ и expression в виде строки, после чего вызывает функцию abort().

/*
//  main.c
//  assert example
//
//  Created by Ariel Feinerman on 23/03/17.
//  Copyright  2017 Feinerman Research, Inc. All rights reserved.
*/

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include <math.h>

int main(int argc, const char * argv[]) {
    double x = -1.0;
    assert(x >= 0.0);
    printf("sqrt(x) = %fn", sqrt(x));   
    
    return EXIT_SUCCESS;
}

Вывод:

Assertion failed: (x >= 0.0), function main, file /Users/ariel/main.c, line 17.

Если макрос NDEBUG определён перед включением <assert.h>, то assert() разворачивается в ((void) 0) и не делает ничего. Используется в отладочных целях.

Пример:

/*
//  main.c
//  assert_example
//
//  Created by Ariel Feinerman on 23/03/17.
//  Copyright  2017 Feinerman Research, Inc. All rights reserved.
*/

#NDEBUG

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include <math.h>

int main(int argc, const char * argv[]) {
    double x = -1.0;
    assert(x >= 0.0);
    printf("sqrt(x) = %fn", sqrt(x));   
    
    return EXIT_SUCCESS;
}

Вывод:

sqrt(x) = nan

Функции atexit(), exit() и abort()

<stdlib.h>

int atexit(void (*func)(void));

Регистрирует функции, вызываемые при нормальном завершении работы программы в порядке, обратном их регистрации. Можно зарегистрировать до 32 функций.

_Noreturn void exit(int exit_code);

Вызывает нормальное завершение программы, возвращает в среду число exit_code. ISO C стандарт определяет всего три возможных значения: 0, EXIT_SUCCESS и EXIT_FAILURE. При этом вызываются функции, зарегистрированные через atexit(), сбрасываются и закрываются потоки ввода — вывода, уничтожаются временные файлы, после чего управление передаётся в среду. Функция exit() вызывается в main() при выполнении return или достижении конца программы.

Главное преимущество exit() в том, что она позволяет завершить программу не только из main(), но и из любой вложенной функции. К примеру, если в глубоко вложенной функции выполнилось (или не выполнилось) некоторое условие, после чего дальнейшее выполнение программы теряет всякий смысл. Подобный приём (early exit) широко используется при написании демонов, системных утилит и парсеров. В интерактивных программах с бесконечным главным циклом exit() можно использовать для выхода из программы при выборе нужного пункта меню.

Пример:

/*
//  main.c
//  exit example
//
//  Created by Ariel Feinerman on 17/03/17.
//  Copyright  2017 Feinerman Research, Inc. All rights reserved.
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

void third_2(void) 
{
    printf("third #2n");          // Does not print.
}

void third_1(void) 
{
    printf("third #1n");          // Does not print.
}

void second(double num) 
{
    printf("second : before exit()n");	// Prints.
    
    if ((num < 1.0f) && (num > -1.0f)) {
        printf("asin(%.1f) = %.3fn", num, asin(num));
        exit(EXIT_SUCCESS);
    }
    else {
        fprintf(stderr, "Error: %.1f is beyond the range [-1.0; 1.0]n", num);
        exit(EXIT_FAILURE);
    }
    
    printf("second : after exit()n");	// Does not print.
}

void first(double num) 
{
    printf("first : before second()n")
    second(num);
    printf("first : after second()n");          // Does not print.
}

int main(int argc, const char * argv[]) 
{
    atexit(third_1); // Register first handler. 
    atexit(third_2); // Register second handler.
    
    first(-3.0f);
    
    return EXIT_SUCCESS;
}

Вывод:

first : before second()
second : before exit()
Error: -3.0 is beyond the range [-1.0; 1.0]
third #2
third #1

_Noreturn void abort(void);

Вызывает аварийное завершение программы, если сигнал не был перехвачен обработчиком сигналов. Временные файлы не уничтожаются, закрытие потоков определяется реализацией. Самое главное отличие вызовов abort() и exit(EXIT_FAILURE) в том, что первый посылает программе сигнал SIGABRT, его можно перехватить и произвести нужные действия перед завершением программы. Записывается дамп памяти программы (core dump file), если они разрешены. При запуске в отладчике он перехватывает сигнал SIGABRT и останавливает выполнение программы, что очень удобно в отладке.

Пример:

/*
//  main.c
//  abort example
//
//  Created by Ariel Feinerman on 17/02/17.
//  Copyright  2017 Feinerman Research, Inc. All rights reserved.
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

void third_2(void) 
{
    printf("third #2n");          // Does not print.
}

void third_1(void) 
{
    printf("third #1n");          // Does not print.
}

void second(double num) 
{
    printf("second : before exit()n");	// Prints.
    
    if ((num < 1.0f) && (num > -1.0f)) {
        printf("asin(%.1f) = %.3fn", num, asin(num));
        exit(EXIT_SUCCESS);
    }
    else {
        fprintf(stderr, "Error: %.1f is beyond the range [-1.0; 1.0]n", num);
        abort();
    }
    
    printf("second : after exit()n");	// Does not print.
}

void first(double num) 
{
    printf("first : before second()n");
    second(num);
    printf("first : after second()n");          // Does not print.
}

int main(int argc, const char * argv[]) 
{
    atexit(third_1); // register first handler 
    atexit(third_2); // register second handler
    
    first(-3.0f);
    
    return EXIT_SUCCESS;
}

Вывод:

first : before second()
second : before exit()
Error: -3.0 is beyond the range [-1.0; 1.0]
Abort trap: 6

Вывод в отладчике:

$ lldb abort_example 
(lldb) target create "abort_example"
Current executable set to 'abort_example' (x86_64).
(lldb) run
Process 22570 launched: '/Users/ariel/abort_example' (x86_64)
first : before second()
second : before exit()
Error: -3.0 is beyond the range [-1.0; 1.0]
Process 22570 stopped
* thread #1: tid = 0x113a8, 0x00007fff89c01286 libsystem_kernel.dylib`__pthread_kill + 10, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
    frame #0: 0x00007fff89c01286 libsystem_kernel.dylib`__pthread_kill + 10
libsystem_kernel.dylib`__pthread_kill:
->  0x7fff89c01286 <+10>: jae    0x7fff89c01290            ; <+20>
    0x7fff89c01288 <+12>: movq   %rax, %rdi
    0x7fff89c0128b <+15>: jmp    0x7fff89bfcc53            ; cerror_nocancel
    0x7fff89c01290 <+20>: retq   
(lldb) 

В случае критической ошибки нужно использовать функцию abort(). К примеру, если при выделении памяти или записи файла произошла ошибка. Любые дальнейшие действия могут усугубить ситуацию. Если завершить выполнение обычным способом, при котором производится сброс потоков ввода — вывода, можно потерять ещё неповрежденные данные и временные файлы, поэтому самым лучшим решением будет записать дамп и мгновенно завершить программу.

В случае же некритической ошибки, например, вы не смогли открыть файл, можно безопасно выйти через exit().

Функции setjmp() и longjmp()

Вот мы и подошли к самому интересному – функциям нелокальных переходов. setjmp() и longjmp() работают по принципу goto, но в отличие от него позволяют перепрыгивать из одного места в другое в пределах всей программы, а не одной функции.

<setjmp.h>

int setjmp(jmp_buf env);

Сохраняет информацию о контексте выполнения программы (регистры микропроцессора и прочее) в env. Возвращает 0, если была вызвана напрямую или value, если из longjmp().

void longjmp(jmp_buf env, int value);

Восстанавливает контекст выполнения программы из env, возвращает управление setjmp() и передаёт ей value.

Пример:

/*
//  main.c
//  setjmp simple
//
//  Created by Ariel Feinerman on 18/02/17.
//  Copyright  2017 Feinerman Research, Inc. All rights reserved.
*/

#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>

static jmp_buf buf;

void second(void) 
{
    printf("second : before longjmp()n");	// prints
    longjmp(buf, 1);						// jumps back to where setjmp was called – making setjmp now return 1
    printf("second : after longjmp()n");	// does not prints
	
    // <- Here is the point that is never reached. All impossible cases like your own house in Miami, your million dollars, your nice girl, etc.
}

void first(void) 
{
    printf("first : before second()n");
    second();
    printf("first : after second()n");          // does not print
}

int main(int argc, const char * argv[]) 
{
    if (!setjmp(buf))
        first();                // when executed, setjmp returned 0
    else                        // when longjmp jumps back, setjmp returns 1
        printf("mainn");       // prints
    
    return EXIT_SUCCESS;
}

Вывод:

first : before second()
second : before longjmp()
main

Используя setjmp() и longjmp() можно реализовать механизм исключений. Во многих языках высокого уровня (например, в Perl) исключения реализованы через них.

Пример:

/*
//  main.c
//  exception simple
//
//  Created by Ariel Feinerman on 18/02/17.
//  Copyright  2017 Feinerman Research, Inc. All rights reserved.
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include <setjmp.h>

#define str(s) #s

static jmp_buf buf;

typedef enum {
    NO_EXCEPTION    = 0,
    RANGE_EXCEPTION = 1,
    NUM_EXCEPTIONS
} exception_t;

static char *exception_name[NUM_EXCEPTIONS] = {
	
    str(NO_EXCEPTION),
    str(RANGE_EXCEPTION)
};

float asin_e(float num) 
{
    if ((num < 1.0f) && (num > -1.0f)) {
        return asinf(num);
    }	
    else {
        longjmp(buf, RANGE_EXCEPTION);        // | @throw  
    }
}

void do_work(float num) 
{
    float res = asin_e(num);
    printf("asin(%f) = %fn", num, res);         
}

int main(int argc, const char * argv[]) 
{
    exception_t exc = NO_EXCEPTION;
    if (!(exc = setjmp(buf))) {        // |	
        do_work(-3.0f);                // | @try
    }                                  // |
    else {                                                                               // | 
        fprintf(stderr, "%s was hadled in %s()n", exception_name[exc], __func__);       // | @catch
    }                                                                                    // | 
	
    return EXIT_SUCCESS;
}

Вывод:

RANGE_EXCEPTION was hadled in main()

Внимание! Функции setjmp() и longjmp() в первую очередь применяются в системном программировании, и их использование в клиентском коде не рекомендуется. Их применение ухудшает читаемость программы и может привести к непредсказуемым ошибкам. Например, что произойдёт, если вы прыгните не вверх по стеку – в вызывающую функцию, а в параллельную, уже завершившую выполнение?

Информация

  • стандарт ISO/IEC C (89/99/11)
  • Single UNIX Specifcation, Version 4, 2016 Edition
  • The Open Group Base Specifcations Issue 7, 2016 Edition (POSIX.1-2008)
  • SEI CERT C Coding Standard
  • cправочная информация среды программирования
  • справочная информация операционной системы (man pages)
  • заголовочные файлы (/usr/include)
  • исходные тексты библиотеки (C Standard Library)

This language bar is your friend. Select your favorite languages!

  • C
fprintf(stderr,"%d is negativen",x);

  • Ada
  • Clojure
  • C++
  • C++
  • C#
  • D
  • Dart
  • Elixir
  • Erlang
  • Fortran
  • Go
  • Haskell
  • JS
  • JS
  • JS
  • Java
  • Java
  • Kotlin
  • Lisp
  • Lua
  • Obj-C
  • PHP
  • Pascal
  • Pascal
  • Perl
  • Python
  • Python
  • Ruby
  • Rust
  • Scala
  • Smalltalk
with Ada.Text_IO;
use Ada.Text_IO;

Put_Line (Standard_Error, Integer'Image (X) & " is negative");

(binding [*out* *err*]
  (println (str x " is negative")))

int main(){
	int x = -2;
	std::cerr << x <<" is negativen";
}

std::cerr << x << " is negativen";

Console.Error.WriteLine($"{x} is negative");

  • Doc

stderr.writeln(x, " is negative");

stderr.write("$x is negative");

  • Doc

IO.puts :stderr, "#{x} is negative"

  • Doc

io:format(standard_error, "~p is negative~n", [X]).

  • Demo
  • Doc

program write_to_stderr
   use iso_fortran_env, only : stderr=>ERROR_UNIT   
   implicit none
   integer :: x=-2
   write(stderr,'(i0," is negative")') x
end program write_to_stderr

fmt.Fprintln(os.Stderr, x, "is negative")

  • Demo

import System.IO (hPutStrLn, stderr)

hPutStrLn stderr (show (x) ++ " is negative")

console.error(x, "is negative");

  • Doc

console.error(`${x} is negative`);

  • Doc

const util = require("util");

console.error(util.format("%d is negative", x));

  • Doc

System.err.printf("%d is negative", x);

System.err.format("%d is negativen",x);

  • Demo
  • Doc

System.err.println("$x is negative")

(format *error-output*
        "~a is negative"
        x)

io.stderr:write(string.format("%d is negativen",x))

NSLog(@"%d is negative",x)

fwrite(STDERR, "{$x} is negativen");

writeln(StdErr , x , ' is negative');

  • Demo
  • Doc

writeln(StdErr, Format('%d is negative',[-2]));

print STDERR "$x is negative";

print >>sys.stderr, "%s is negative" % x

print(x, "is negative", file=sys.stderr)

warn "#{x} is negative"
$stderr.puts "%d is negative" % x

  • Doc

eprintln!("{} is negative", x);

  • Demo
  • Doc

System.err.println(s"$x is negative")

" implementation: Visual Works "

OS.Stderr 
  nextPutAll: x asString;
  nextPutAll: ' is negative';
  nextPut: Character cr.

  • C
fprintf(stderr,"%d is negativen",x);

  • Ada
Put_Line (Standard_Error, Integer'Image (X) & " is negative");

  • Clojure
(binding [*out* *err*]
  (println (str x " is negative")))

  • C++
int main(){
	int x = -2;
	std::cerr << x <<" is negativen";
}

  • C++
std::cerr << x << " is negativen";

  • C#
Console.Error.WriteLine($"{x} is negative");

  • D
stderr.writeln(x, " is negative");

  • Dart
stderr.write("$x is negative");

  • Elixir
IO.puts :stderr, "#{x} is negative"

  • Erlang
io:format(standard_error, "~p is negative~n", [X]).

  • Fortran
program write_to_stderr
   use iso_fortran_env, only : stderr=>ERROR_UNIT   
   implicit none
   integer :: x=-2
   write(stderr,'(i0," is negative")') x
end program write_to_stderr

  • Go
fmt.Fprintln(os.Stderr, x, "is negative")

  • Haskell
hPutStrLn stderr (show (x) ++ " is negative")

  • JS
console.error(x, "is negative");

  • JS
console.error(`${x} is negative`);

  • JS
console.error(util.format("%d is negative", x));

  • Java
System.err.printf("%d is negative", x);

  • Java
System.err.format("%d is negativen",x);

  • Kotlin
System.err.println("$x is negative")

  • Lisp
(format *error-output*
        "~a is negative"
        x)

  • Lua
io.stderr:write(string.format("%d is negativen",x))

  • Obj-C
NSLog(@"%d is negative",x)

  • PHP
fwrite(STDERR, "{$x} is negativen");

  • Pascal
writeln(StdErr , x , ' is negative');

  • Pascal
writeln(StdErr, Format('%d is negative',[-2]));

  • Perl
print STDERR "$x is negative";

  • Python
print >>sys.stderr, "%s is negative" % x

  • Python
print(x, "is negative", file=sys.stderr)

  • Ruby
warn "#{x} is negative"
$stderr.puts "%d is negative" % x

  • Rust
eprintln!("{} is negative", x);

  • Scala
System.err.println(s"$x is negative")

  • Smalltalk
OS.Stderr 
  nextPutAll: x asString;
  nextPutAll: ' is negative';
  nextPut: Character cr.

Stderr in C

Introduction to Stderr in C

In C programming language, there are different file descriptors which are also known as standard output. There are 3 standards I/O devices that are stdin for standard input, stdout for standard output, stderr for error message output. In this article, we are discussing stderr which used to map on the terminal output. It generates the error message that displays on the output devices and not anywhere else. These three standards I/O devices are the streams that are declared in the header file stdio.h file. Stderr is directly linked by OS to either window terminal or Unix terminal.

Functions of Stderr in C with Examples

Stderr is the standard error message that is used to print the output on the screen or windows terminal. Stderr is used to print the error on the output screen or window terminal. Stderr is also one of the command output as stdout, which is logged anywhere by default. So the output message goes to the console or terminal and if once the terminal is closed the output message is gone forever, where if we want to store such output messages or error messages then we have to redirect it to the files. Stdout and stderr are standards in which stdout is fully buffered whereas stderr is not fully buffered because stdout will completely remove the messages or flushes whenever the program is asked to do explicitly and stderr writes the output message or error message immediately to the console or the window terminal. Let us see how the stderr is used to print.

Example #1

Code:

#include <stdio.h>
int main()
{
fprintf(stderr, "Educba Training");
}

Output:

Stderr in C-1.1

In the above program, we are printing the message on the output screen. This can be done by using both Stdout and stderr.

In an earlier version of v6 both output and error was sent to the file also which required the manual cleanup by the user as there was no stderr in that version. So stderr is used to do the opposite of the above version where stderr is used to send the message to the file and stdout is used to print the output on the console.

The stderr cannot be redirected to any file instead they are used to print on the same console, whereas stdout can be used for the redirection. The printf() statements used in the programs are used stdout devices by default. So if we use fprintf() statement then these are used to send the output message to the file stdout. If we use stderr in the fprintf() statement then this will not redirect the output message to the file instead it is printed on the same console. The above situation can be explained by the below programs.

Example #2

Code:

#include <stdio.h>
int main()
{
printf("This is message 1n");
printf("This is message 2n");
printf("This is message 3n");
return(0);
}

Ouput:

Stderr in C-1.2

This above program uses printf() statement where stdout uses these statements to print the output message on the console. Whereas the above program can also be written using frprintf() statements to do a similar job as the above program. This can be written as below:

#include <stdio.h>
int main()
{
fprintf(stdout,"This is message 1n");
fprintf(stdout,"This is message 2n");
fprintf(stdout,"This is message 3n");
return(0);
}

Output:

Example-1.3

In the above program, we use fprintf() statement where it redirects the output message and send it to the file using stdout. Now let us see if we use stderr it will not redirect the output message to the file instead it works the same as the above program it will print the output on the console. This can be done using the below program.

Example #3

Code:

#include <stdio.h>
int main()
{
fprintf(stdout,"This is message 1n");
fprintf(stderr,"This is message 2n");
fprintf(stdout,"This is message 3n");
return(0);
}

Output:

Example-1.4

In the above program, the second fprintf() statement uses stderr and when we try to redirect the output message only the output message of first and third fprintf() statements are redirected or send to the file whereas the second fprintf() statement which uses stderr cannot be redirected so it prints the output message on the console.

The fprintf(stderr, “”) is the statement is used by both stdout and stderr to print the output message or error message within the double quotes to the window terminal or console.

In C programming language, as standard I/O is buffered therefore the error message is sent to the stderr which appears on the console as out of sequence where another text is sent to the standard output such as stdout. Stderr is used to print the error message to the output console and hence this is used in the program where we want the output to be fetched directly into the other program where it prints the error message directly on the console. Stderr prints the output message on the windows terminal even if the stdout is redirected. There are two different functions that stderr include are fprintf(), fputs(). If we use it for writing the out message to the file then we have to use: FILE *stderr. This stderr is a standard error stream is the default destination for printing the output message as an error message.

Conclusion

This article is based on the standard I/O in C programming language. 3 different standards in C are stdin, stdout, and stderr and in this article, we are discussing stderr. Stderr is the standard error message which prints the output message or error message to the console or windows terminal. The stderr is also unlike stdout where stdout prints the output message to the terminal and also can redirect the output message to the file whereas the stderr also prints the output message or error message immediately to the output terminal or console, but it cannot redirect it to the other file.

Recommended Articles

This is a guide to Stderr in C. Here we also discuss the Introduction and working of stderr in c along with different examples and its code implementation. You may also have a look at the following articles to learn more –

  1. Linked List in C
  2. Conditional Operator in C
  3. Memory Allocation in C
  4. sizeof() in C

Понравилась статья? Поделить с друзьями:
  • Print req error i o error dev sda sector
  • Print reg error i o error dev sda sector
  • Print mysqli error
  • Primary launch error 206
  • Print mode error kyocera km 2050