我想打印一个数字日志或使用终端write
一个讯号处理器中(或任何异步安全功能)。 我宁愿不使用缓冲I / O。
有一个简单的和推荐的方式做到这一点?
例如代替printf
,下面我宁愿write
(或任何ASYN安全功能)。
void signal_handler(int sig)
{
pid_t pid;
int stat;
int old_errno = errno;
while((pid = waitpid(-1, &stat, WNOHANG)) > 0)
printf("child %d terminated\n", pid);
errno = old_errno;
return;
}
打印字符串很容易。 代替的printf
上述我可以使用(而不打印pid
):
write(STDOUT_FILENO, "child terminated", 16);
如果你真的坚持从信号处理程序做印刷,你基本上有两个选择:
块的信号,除非你处理的信号创建一个专门的线程。 这种特殊的线程可以简单地执行for (;;) pause();
而且由于pause
是异步信号安全,信号处理程序被允许使用它想要的任何功能; 它不仅仅局限于异步信号安全功能。 在另一方面,它也有访问一个线程安全的方式共享资源,因为你现在正在处理的线程。
编写自己的代码的整数转换成十进制。 它使用的只是一个简单的循环%10
和/10
剥离最后一位数字,并将其存储到短阵。
不过,我会极力推荐此操作出来的信号处理器,采用了自管伎俩或相似。
实现自己的异步信号安全snprintf("%d
,用write
这不是因为我想,坏如何为int转换为字符串使用C? 有几个实现。
下面计数的POSIX程序到stdout收到SIGINT到目前为止倍,您可以与触发的数量Ctrl + C
。
您可以退出该程序Ctrl + \
(SIGQUIT)。
main.c中:
#define _XOPEN_SOURCE 700
#include <assert.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
/* Calculate the minimal buffer size for a given type.
*
* Here we overestimate and reserve 8 chars per byte.
*
* With this size we could even print a binary string.
*
* - +1 for NULL terminator
* - +1 for '-' sign
*
* A tight limit for base 10 can be found at:
* https://stackoverflow.com/questions/8257714/how-to-convert-an-int-to-string-in-c/32871108#32871108
*
* TODO: get tight limits for all bases, possibly by looking into
* glibc's atoi: https://stackoverflow.com/questions/190229/where-is-the-itoa-function-in-linux/52127877#52127877
*/
#define ITOA_SAFE_STRLEN(type) sizeof(type) * CHAR_BIT + 2
/* async-signal-safe implementation of integer to string conversion.
*
* Null terminates the output string.
*
* The input buffer size must be large enough to contain the output,
* the caller must calculate it properly.
*
* @param[out] value Input integer value to convert.
* @param[out] result Buffer to output to.
* @param[in] base Base to convert to.
* @return Pointer to the end of the written string.
*/
char *itoa_safe(intmax_t value, char *result, int base) {
intmax_t tmp_value;
char *ptr, *ptr2, tmp_char;
if (base < 2 || base > 36) {
return NULL;
}
ptr = result;
do {
tmp_value = value;
value /= base;
*ptr++ = "ZYXWVUTSRQPONMLKJIHGFEDCBA9876543210123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[35 + (tmp_value - value * base)];
} while (value);
if (tmp_value < 0)
*ptr++ = '-';
ptr2 = result;
result = ptr;
*ptr-- = '\0';
while (ptr2 < ptr) {
tmp_char = *ptr;
*ptr--= *ptr2;
*ptr2++ = tmp_char;
}
return result;
}
volatile sig_atomic_t global = 0;
void signal_handler(int sig) {
char buf[ITOA_SAFE_STRLEN(sig_atomic_t)];
enum { base = 10 };
char *end;
end = itoa_safe(global, buf, base);
*end = '\n';
write(STDOUT_FILENO, buf, end - buf + 1);
global += 1;
signal(sig, signal_handler);
}
int main(int argc, char **argv) {
/* Unit test itoa_safe. */
{
typedef struct {
intmax_t n;
int base;
char out[1024];
} InOut;
char result[1024];
size_t i;
InOut io;
InOut ios[] = {
/* Base 10. */
{0, 10, "0"},
{1, 10, "1"},
{9, 10, "9"},
{10, 10, "10"},
{100, 10, "100"},
{-1, 10, "-1"},
{-9, 10, "-9"},
{-10, 10, "-10"},
{-100, 10, "-100"},
/* Base 2. */
{0, 2, "0"},
{1, 2, "1"},
{10, 2, "1010"},
{100, 2, "1100100"},
{-1, 2, "-1"},
{-100, 2, "-1100100"},
/* Base 35. */
{0, 35, "0"},
{1, 35, "1"},
{34, 35, "Y"},
{35, 35, "10"},
{100, 35, "2U"},
{-1, 35, "-1"},
{-34, 35, "-Y"},
{-35, 35, "-10"},
{-100, 35, "-2U"},
};
for (i = 0; i < sizeof(ios)/sizeof(ios[0]); ++i) {
io = ios[i];
itoa_safe(io.n, result, io.base);
if (strcmp(result, io.out)) {
printf("%ju %d %s\n", io.n, io.base, io.out);
assert(0);
}
}
}
/* Handle the signals. */
if (argc > 1 && !strcmp(argv[1], "1")) {
signal(SIGINT, signal_handler);
while(1);
}
return EXIT_SUCCESS;
}
编译并运行:
gcc -std=c99 -Wall -Wextra -o main main.c
./main 1
按下Ctrl + C 15次后,该终端显示:
^C0
^C1
^C2
^C3
^C4
^C5
^C6
^C7
^C8
^C9
^C10
^C11
^C12
^C13
^C14
下面是创建一个更复杂的格式字符串相关的程序: 如何避免在信号处理用printf?
经测试在Ubuntu 18.04。 GitHub的上游 。
如果您坚持使用一个讯号处理器中xprintf()你总是可以推出自己的版本,不依赖于缓冲I / O:
#include <stdarg.h> /* vsnprintf() */
void myprintf(FILE *fp, char *fmt, ...)
{
char buff[512];
int rc,fd;
va_list argh;
va_start (argh, fmt);
rc = vsnprintf(buff, sizeof buff, fmt, argh);
if (rc < 0 || rc >= sizeof buff) {
rc = sprintf(buff, "Argh!: %d:\n", rc);
}
if (!fp) fp = stderr;
fd = fileno(fp);
if (fd < 0) return;
if (rc > 0) write(fd, buff, rc);
return;
}