Implementa il tuo segnale asincrono sicuro snprintf("%d
e usawrite
Non è così male come pensavo, come convertire un int in una stringa in C? ha diverse implementazioni.
Poiché ci sono solo due tipi interessanti di dati a cui possono accedere i gestori di segnali:
sig_atomic_t
globali
int
argomento del segnale
questo fondamentalmente copre tutti i casi d'uso interessanti.
Il fatto che strcpy
sia anche sicuro per i segnali rende le cose ancora migliori.
Il programma POSIX seguente stampa allo stdout il numero di volte che ha ricevuto SIGINT finora, che è possibile attivare con Ctrl + C
, e l'ID segnale e.
È possibile uscire dal programma con 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>
#define ITOA_SAFE_STRLEN(type) sizeof(type) * CHAR_BIT + 2
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 key_str[] = "count, sigid: ";
char buf[2 * ITOA_SAFE_STRLEN(sig_atomic_t) + sizeof(key_str)];
enum { base = 10 };
char *end;
end = buf;
strcpy(end, key_str);
end += sizeof(key_str);
end = itoa_safe(global, end, base);
*end++ = ' ';
end = itoa_safe(sig, end, base);
*end++ = '\n';
write(STDOUT_FILENO, buf, end - buf);
global += 1;
signal(sig, signal_handler);
}
int main(int argc, char **argv) {
{
typedef struct {
intmax_t n;
int base;
char out[1024];
} InOut;
char result[1024];
size_t i;
InOut io;
InOut ios[] = {
{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"},
{0, 2, "0"},
{1, 2, "1"},
{10, 2, "1010"},
{100, 2, "1100100"},
{-1, 2, "-1"},
{-100, 2, "-1100100"},
{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);
}
}
}
if (argc > 1 && !strcmp(argv[1], "1")) {
signal(SIGINT, signal_handler);
while(1);
}
return EXIT_SUCCESS;
}
Compila ed esegui:
gcc -std=c99 -Wall -Wextra -o main main.c
./main 1
Dopo aver premuto Ctrl + C quindici volte, il terminale mostra:
^Ccount, sigid: 0 2
^Ccount, sigid: 1 2
^Ccount, sigid: 2 2
^Ccount, sigid: 3 2
^Ccount, sigid: 4 2
^Ccount, sigid: 5 2
^Ccount, sigid: 6 2
^Ccount, sigid: 7 2
^Ccount, sigid: 8 2
^Ccount, sigid: 9 2
^Ccount, sigid: 10 2
^Ccount, sigid: 11 2
^Ccount, sigid: 12 2
^Ccount, sigid: 13 2
^Ccount, sigid: 14 2
dov'è 2
il numero del segnale per SIGINT
.
Testato su Ubuntu 18.04. GitHub a monte .
printf
chiamata in quel segnale? Cancellalo.