Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.
signal() was the original UNIX API for setting signal dispositions. It is simpler than sigaction() but less portable — its behaviour varies across UNIX implementations. For production code always use sigaction(). But signal() is important to understand because you’ll see it in legacy code everywhere.
In Linux, signal() is actually a glibc wrapper that calls sigaction() internally.
The raw prototype looks confusing because it uses function pointers:
#include <signal.h>
/* Raw prototype — hard to read */
void ( *signal(int sig, void (*handler)(int)) ) (int);
/* Simplified using typedef — much cleaner */
typedef void (*sighandler_t)(int);
sighandler_t signal(int sig, sighandler_t handler);
Arguments:
| Argument | Meaning |
|---|---|
| sig | Signal number to change disposition for (e.g. SIGINT) |
| handler | New disposition: address of handler function, SIG_DFL, or SIG_IGN |
Return value: The previous disposition of the signal (so you can save and restore it). Returns SIG_ERR on error.
/* Install a handler, save old disposition, then restore it
Compile: gcc -o signal_save signal_save.c
Run: ./signal_save */
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
static void newHandler(int sig)
{
printf("newHandler called for signal %d\n", sig);
}
int main(void)
{
/* sighandler_t is typedef void(*)(int) */
void (*oldHandler)(int);
/* Install newHandler and save the old disposition */
oldHandler = signal(SIGINT, newHandler);
if (oldHandler == SIG_ERR) {
perror("signal");
return 1;
}
printf("newHandler installed. Press Ctrl+C twice.\n");
sleep(5); /* newHandler fires on Ctrl+C here */
/* Restore original disposition (SIG_DFL = terminate) */
if (signal(SIGINT, oldHandler) == SIG_ERR) {
perror("signal restore");
return 1;
}
printf("Old handler restored. Ctrl+C will now terminate.\n");
sleep(5); /* Default action fires on Ctrl+C here */
return 0;
}
/* Pattern: temporarily change, do work, restore
Compile: gcc -o temp_handler temp_handler.c */
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
static void tempHandler(int sig)
{
write(1, "Caught during protected work!\n", 30);
}
int main(void)
{
void (*prev)(int);
printf("Starting protected work...\n");
/* Install temporary handler, save old */
prev = signal(SIGINT, tempHandler);
/* === Protected work — SIGINT caught by tempHandler === */
int i;
for (i = 0; i < 5; i++) {
printf("Protected step %d\n", i + 1);
sleep(1);
}
/* Restore old disposition */
signal(SIGINT, prev);
printf("Protected work done. Ctrl+C is back to default.\n");
sleep(3);
return 0;
}
/* Proper error handling when calling signal()
Compile: gcc -o sig_err sig_err.c */
#include <stdio.h>
#include <signal.h>
#include <errno.h>
static void handler(int sig)
{
write(1, "Handler\n", 8);
}
int main(void)
{
/* signal() returns SIG_ERR on failure */
if (signal(SIGINT, handler) == SIG_ERR) {
perror("signal(SIGINT)");
return 1;
}
/* Attempt on SIGKILL — should fail (SIG_ERR) */
if (signal(SIGKILL, handler) == SIG_ERR) {
/* This always prints because SIGKILL cannot be caught */
perror("signal(SIGKILL)");
}
/* signal() returns SIG_DFL or SIG_IGN if the signal had
one of those as previous disposition */
void (*prev)(int);
prev = signal(SIGUSR1, handler);
if (prev == SIG_DFL)
printf("SIGUSR1 previously had default action\n");
else if (prev == SIG_IGN)
printf("SIGUSR1 was previously ignored\n");
else
printf("SIGUSR1 previously had a custom handler\n");
pause(); /* wait for signal */
return 0;
}
Sending Signals with kill() — How one process signals another
Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.
