google-site-verification: google61fe8ba583a51912.html
Signal Handling in C: Complete Guide

Introduction to Signal Handling

Signals are software interrupts sent to a program to indicate that an important event has occurred. They provide a way to handle asynchronous events such as user interrupts (Ctrl+C), illegal memory access, or timer expiration. Understanding signal handling is crucial for writing robust and responsive C programs.


Signal Architecture Overview

Signal Handling Architecture ├── Signal Sources │ ├── User (Ctrl+C, Ctrl+Z) │ ├── Kernel (SIGSEGV, SIGFPE) │ ├── Process (kill(), raise()) │ └── Timer (alarm(), setitimer()) ├── Signal Delivery │ ├── Pending Signals │ ├── Blocked Signals │ ├── Signal Mask │ └── Signal Disposition └── Signal Handling ├── Default Action ├── Ignore Signal ├── User-defined Handler └── Signal-safe Functions

Common Signals in C

SignalValueDefault ActionDescription
SIGINT2TerminateInterrupt from keyboard (Ctrl+C)
SIGQUIT3Core dumpQuit from keyboard (Ctrl+)
SIGILL4Core dumpIllegal instruction
SIGABRT6Core dumpAbort signal from abort()
SIGFPE8Core dumpFloating point exception
SIGSEGV11Core dumpInvalid memory reference
SIGTERM15TerminateTermination signal
SIGALRM14TerminateTimer signal from alarm()
SIGUSR110TerminateUser-defined signal 1
SIGUSR212TerminateUser-defined signal 2
SIGCHLD17IgnoreChild process stopped or terminated
SIGCONT18ContinueContinue if stopped
SIGSTOP19StopStop process (cannot be caught)
SIGTSTP20StopStop from terminal (Ctrl+Z)

Basic Signal Handling

1. Using signal() Function

#include <stdio.h> #include <signal.h> #include <unistd.h> // Signal handler function void signalHandler(int signum) { printf("\nSignal %d received!\n", signum); if (signum == SIGINT) { printf(" Caught SIGINT (Ctrl+C)\n"); printf(" Press Ctrl+C again to exit\n"); } else if (signum == SIGTERM) { printf(" Caught SIGTERM\n"); printf(" Exiting gracefully...\n"); } } int main() { // Register signal handlers signal(SIGINT, signalHandler); signal(SIGTERM, signalHandler); printf("Signal handling example. PID: %d\n", getpid()); printf("Try pressing Ctrl+C or send SIGTERM\n"); // Infinite loop - wait for signals while (1) { printf("Working...\n"); sleep(2); } return 0; }

2. Ignoring Signals

#include <stdio.h> #include <signal.h> #include <unistd.h> int main() { printf("Ignoring SIGINT (Ctrl+C) and SIGQUIT (Ctrl+\\)\n"); printf("Press Ctrl+C or Ctrl+\\ - nothing will happen\n"); printf("Press Ctrl+Z to stop (SIGTSTP)\n\n"); // Ignore these signals signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); int count = 0; while (count < 10) { printf("Working... %d\n", ++count); sleep(1); } // Restore default behavior signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); printf("\nDefault behavior restored\n"); printf("Next Ctrl+C will terminate\n"); while (1) { printf("Working...\n"); sleep(1); } return 0; }

Advanced Signal Handling with sigaction()

1. Basic sigaction() Usage

#include <stdio.h> #include <signal.h> #include <string.h> #include <unistd.h> // Signal handler void handler(int signum) { printf("Signal %d received\n", signum); } int main() { struct sigaction sa; // Set up sigaction structure memset(&sa, 0, sizeof(sa)); sa.sa_handler = handler; sigemptyset(&sa.sa_mask); // No additional signals blocked sa.sa_flags = 0; // No flags // Register handler for SIGINT if (sigaction(SIGINT, &sa, NULL) == -1) { perror("sigaction"); return 1; } printf("SIGINT handler installed with sigaction\n"); printf("Press Ctrl+C to trigger\n"); pause(); // Wait for signal return 0; }

2. Getting Signal Information

#include <stdio.h> #include <signal.h> #include <string.h> #include <unistd.h> #include <stdlib.h> // Advanced handler with signal information void advancedHandler(int signum, siginfo_t *info, void *context) { printf("\n=== Signal Information ===\n"); printf("Signal number: %d\n", signum); printf("Signal code: %d\n", info->si_code); printf("Sender PID: %d\n", info->si_pid); printf("Sender UID: %d\n", info->si_uid); printf("Signal value: %d\n", info->si_value.sival_int); switch (info->si_code) { case SI_USER: printf("Sent by: kill() or raise()\n"); break; case SI_QUEUE: printf("Sent by: sigqueue()\n"); break; case SI_TIMER: printf("Sent by: timer expiration\n"); break; case SI_ASYNCIO: printf("Sent by: asynchronous I/O completion\n"); break; case SI_MESGQ: printf("Sent by: message queue state change\n"); break; } } int main() { struct sigaction sa; // Set up sigaction with extended information memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = advancedHandler; sa.sa_flags = SA_SIGINFO; // Get extended info if (sigaction(SIGUSR1, &sa, NULL) == -1) { perror("sigaction"); return 1; } printf("Advanced handler for SIGUSR1 installed\n"); printf("PID: %d\n", getpid()); printf("Send SIGUSR1 from another terminal with: kill -USR1 %d\n", getpid()); printf("Or send with value: kill -USR1 %d\n", getpid()); printf("\nWaiting for signal...\n"); pause(); return 0; }

3. Blocking Signals with Signal Masks

#include <stdio.h> #include <signal.h> #include <unistd.h> int signalReceived = 0; void handler(int signum) { signalReceived = 1; printf("Signal %d received and handled\n", signum); } int main() { sigset_t newmask, oldmask, pendmask; // Set up signal handler signal(SIGINT, handler); // Block SIGINT sigemptyset(&newmask); sigaddset(&newmask, SIGINT); // Block the signal if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) == -1) { perror("sigprocmask"); return 1; } printf("SIGINT is now blocked\n"); printf("Try pressing Ctrl+C - signal will be pending\n"); sleep(5); // Check pending signals sigpending(&pendmask); if (sigismember(&pendmask, SIGINT)) { printf("\nSIGINT is pending\n"); } else { printf("\nNo pending signals\n"); } // Unblock the signal printf("Unblocking SIGINT...\n"); sigprocmask(SIG_SETMASK, &oldmask, NULL); printf("Signal should be delivered now\n"); sleep(1); if (signalReceived) { printf("Signal was handled successfully\n"); } return 0; }

Practical Signal Handling Examples

1. Graceful Shutdown

#include <stdio.h> #include <signal.h> #include <unistd.h> #include <stdlib.h> #include <stdbool.h> volatile sig_atomic_t shutdownRequested = 0; void shutdownHandler(int signum) { shutdownRequested = 1; } int main() { // Set up handlers for graceful shutdown struct sigaction sa; sa.sa_handler = shutdownHandler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); printf("Server started. PID: %d\n", getpid()); printf("Press Ctrl+C to initiate graceful shutdown\n"); int iteration = 0; while (!shutdownRequested) { printf("Processing iteration %d...\n", ++iteration); // Simulate work with cleanup points for (int i = 0; i < 10; i++) { if (shutdownRequested) break; printf(" Sub-task %d\n", i); sleep(1); } if (shutdownRequested) { printf("\nShutdown requested. Cleaning up...\n"); // Perform cleanup sleep(2); // Simulate cleanup printf("Cleanup complete. Exiting.\n"); break; } } printf("Server stopped gracefully\n"); return 0; }

2. Timer Signals

#include <stdio.h> #include <signal.h> #include <unistd.h> #include <sys/time.h> int timerCount = 0; void timerHandler(int signum) { printf("Timer tick %d\n", ++timerCount); } int main() { struct itimerval timer; // Set up signal handler signal(SIGALRM, timerHandler); // Configure timer timer.it_value.tv_sec = 1; // First expiration after 1 second timer.it_value.tv_usec = 0; timer.it_interval.tv_sec = 2; // Then every 2 seconds timer.it_interval.tv_usec = 0; // Start timer if (setitimer(ITIMER_REAL, &timer, NULL) == -1) { perror("setitimer"); return 1; } printf("Timer started. Will fire every 2 seconds.\n"); printf("Press Ctrl+C to stop\n"); // Wait for 10 seconds sleep(10); // Stop timer timer.it_value.tv_sec = 0; timer.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &timer, NULL); printf("\nTimer stopped. Total ticks: %d\n", timerCount); return 0; }

3. Child Process Monitoring

#include <stdio.h> #include <signal.h> #include <unistd.h> #include <sys/wait.h> #include <stdlib.h> void childHandler(int signum) { int status; pid_t pid; // Wait for all terminated children while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { if (WIFEXITED(status)) { printf("Child %d exited with status %d\n", pid, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf("Child %d killed by signal %d\n", pid, WTERMSIG(status)); } } } int main() { struct sigaction sa; // Set up SIGCHLD handler sa.sa_handler = childHandler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; sigaction(SIGCHLD, &sa, NULL); // Create child processes for (int i = 0; i < 3; i++) { pid_t pid = fork(); if (pid == 0) { // Child process printf("Child %d started\n", getpid()); sleep(2 + i); printf("Child %d exiting\n", getpid()); exit(i); } } printf("Parent waiting for children...\n"); // Parent continues working for (int i = 0; i < 10; i++) { printf("Parent working... %d\n", i); sleep(1); } printf("Parent exiting\n"); return 0; }

4. Signal Queue (POSIX Real-time Signals)

#include <stdio.h> #include <signal.h> #include <unistd.h> #include <stdlib.h> #define MAX_SIGNALS 5 void rtHandler(int signum, siginfo_t *info, void *context) { printf("Received signal %d with value %d\n", signum, info->si_value.sival_int); } int main() { struct sigaction sa; union sigval value; // Set up handler for real-time signal sa.sa_sigaction = rtHandler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_SIGINFO; if (sigaction(SIGRTMIN, &sa, NULL) == -1) { perror("sigaction"); return 1; } printf("Real-time signal handler installed\n"); printf("PID: %d\n", getpid()); printf("Sending signals to self...\n"); // Queue multiple signals for (int i = 0; i < MAX_SIGNALS; i++) { value.sival_int = i * 10; if (sigqueue(getpid(), SIGRTMIN, value) == -1) { perror("sigqueue"); } printf("Queued signal with value %d\n", value.sival_int); } printf("\nWaiting for signals to be delivered...\n"); sleep(2); return 0; }

Signal-Safe Functions

1. Async-Signal-Safe Functions

#include <stdio.h> #include <signal.h> #include <unistd.h> #include <string.h> // Signal-safe function list (POSIX) // write(), read(), open(), close(), stat(), etc. // NOT safe: printf(), malloc(), free(), etc. volatile sig_atomic_t flag = 0; void safeHandler(int signum) { // Using write() which is async-signal-safe const char *msg = "Signal caught!\n"; write(STDOUT_FILENO, msg, strlen(msg)); flag = 1; } int main() { signal(SIGINT, safeHandler); printf("Signal handler uses async-signal-safe write()\n"); printf("Press Ctrl+C\n"); while (!flag) { pause(); } printf("Program continuing after signal\n"); return 0; }

2. Unsafe vs Safe Operations

#include <stdio.h> #include <signal.h> #include <unistd.h> #include <string.h> // UNSAFE handler - uses printf void unsafeHandler(int signum) { // printf is NOT async-signal-safe! printf("Signal %d received\n", signum); // DANGER! } // SAFE handler - uses write void safeHandler(int signum) { const char *msg = "Signal received\n"; write(STDOUT_FILENO, msg, strlen(msg)); // Safe } int main() { printf("Compare safe vs unsafe handlers\n"); // Test unsafe handler signal(SIGUSR1, unsafeHandler); printf("\nUnsafe handler (using printf):\n"); raise(SIGUSR1); // Test safe handler signal(SIGUSR2, safeHandler); printf("\nSafe handler (using write):\n"); raise(SIGUSR2); return 0; }

3. Self-Pipe Trick

#include <stdio.h> #include <signal.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <errno.h> int pipefd[2]; void signalHandler(int signum) { // Write to pipe (async-signal-safe) int saved_errno = errno; write(pipefd[1], "x", 1); errno = saved_errno; } int main() { // Create pipe if (pipe(pipefd) == -1) { perror("pipe"); return 1; } // Set non-blocking on read end int flags = fcntl(pipefd[0], F_GETFL); fcntl(pipefd[0], F_SETFL, flags | O_NONBLOCK); // Set up signal handler signal(SIGINT, signalHandler); signal(SIGTERM, signalHandler); printf("Self-pipe trick example. PID: %d\n", getpid()); printf("Signals will be handled via pipe\n"); char buf[1024]; int running = 1; while (running) { // Do some work printf("Working...\n"); // Check for signals using select fd_set readfds; FD_ZERO(&readfds); FD_SET(pipefd[0], &readfds); struct timeval tv; tv.tv_sec = 2; tv.tv_usec = 0; int ret = select(pipefd[0] + 1, &readfds, NULL, NULL, &tv); if (ret > 0 && FD_ISSET(pipefd[0], &readfds)) { // Read from pipe to clear it int n = read(pipefd[0], buf, sizeof(buf)); if (n > 0) { printf("\nReceived %d signal(s)\n", n); if (n >= 3) running = 0; // Exit after 3 signals } } } printf("Exiting...\n"); close(pipefd[0]); close(pipefd[1]); return 0; }

Advanced Signal Techniques

1. Signal Sets Operations

#include <stdio.h> #include <signal.h> void printSignalSet(const char *name, sigset_t *set) { printf("%s contains: ", name); for (int i = 1; i <= 31; i++) { if (sigismember(set, i)) { printf("%d ", i); } } printf("\n"); } int main() { sigset_t set1, set2, set3; // Initialize empty set sigemptyset(&set1); printf("After sigemptyset: "); printSignalSet("set1", &set1); // Add signals sigaddset(&set1, SIGINT); sigaddset(&set1, SIGTERM); sigaddset(&set1, SIGUSR1); printf("After adding SIGINT, SIGTERM, SIGUSR1: "); printSignalSet("set1", &set1); // Fill set sigfillset(&set2); printf("\nAfter sigfillset: "); printSignalSet("set2", &set2); // Remove some signals sigdelset(&set2, SIGINT); sigdelset(&set2, SIGTERM); printf("After removing SIGINT, SIGTERM: "); printSignalSet("set2", &set2); // Set operations sigemptyset(&set3); sigaddset(&set3, SIGINT); sigaddset(&set3, SIGQUIT); // Check membership printf("\nMembership checks:\n"); printf("SIGINT in set1? %s\n", sigismember(&set1, SIGINT) ? "yes" : "no"); printf("SIGQUIT in set1? %s\n", sigismember(&set1, SIGQUIT) ? "yes" : "no"); return 0; }

2. sigsuspend() for Atomic Waiting

#include <stdio.h> #include <signal.h> #include <unistd.h> int signalReceived = 0; void handler(int signum) { signalReceived = 1; } int main() { sigset_t newmask, oldmask; signal(SIGUSR1, handler); // Block SIGUSR1 sigemptyset(&newmask); sigaddset(&newmask, SIGUSR1); sigprocmask(SIG_BLOCK, &newmask, &oldmask); printf("Waiting for SIGUSR1 with sigsuspend\n"); printf("Send signal from another terminal: kill -USR1 %d\n", getpid()); // Critical section - signals are blocked // Do some preparation work printf("Preparing...\n"); sleep(1); // Atomically unblock signals and wait sigsuspend(&oldmask); // After signal, signals are blocked again printf("Signal received! Continuing...\n"); // Restore original mask sigprocmask(SIG_SETMASK, &oldmask, NULL); return 0; }

3. sigaltstack() - Alternate Signal Stack

#include <stdio.h> #include <signal.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #define STACK_SIZE SIGSTKSZ * 2 // Handler using alternate stack void stackHandler(int signum) { char buffer[1000]; // Large stack allocation printf("Handler running on alternate stack\n"); printf("Stack pointer difference: %ld\n", (long)&buffer - (long)__builtin_frame_address(0)); } int main() { stack_t ss; struct sigaction sa; // Allocate alternate stack ss.ss_sp = malloc(STACK_SIZE); if (ss.ss_sp == NULL) { perror("malloc"); return 1; } ss.ss_size = STACK_SIZE; ss.ss_flags = 0; if (sigaltstack(&ss, NULL) == -1) { perror("sigaltstack"); free(ss.ss_sp); return 1; } // Set up handler to use alternate stack sa.sa_handler = stackHandler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_ONSTACK; sigaction(SIGUSR1, &sa, NULL); printf("Handler will use alternate stack\n"); printf("Send SIGUSR1: kill -USR1 %d\n", getpid()); pause(); free(ss.ss_sp); return 0; }

Error Handling with Signals

1. Segmentation Fault Handling

#include <stdio.h> #include <signal.h> #include <setjmp.h> jmp_buf env; void segfaultHandler(int signum) { printf("\nSegmentation fault caught!\n"); printf("Signal %d (SIGSEGV) occurred\n", signum); printf("Jumping back to safe point...\n"); longjmp(env, 1); } int main() { // Set up segfault handler signal(SIGSEGV, segfaultHandler); if (setjmp(env) == 0) { // Normal execution printf("Attempting dangerous operation...\n"); // Cause a segfault int *p = NULL; *p = 42; // This will crash printf("This line won't be reached\n"); } else { // After longjmp from handler printf("Recovered from segmentation fault!\n"); printf("Program continuing safely\n"); } printf("Program completed normally\n"); return 0; }

2. Floating Point Exception Handling

#include <stdio.h> #include <signal.h> #include <fenv.h> void fpeHandler(int signum) { printf("\nFloating point exception caught!\n"); printf("Signal %d (SIGFPE) occurred\n", signum); // Clear the exception feclearexcept(FE_ALL_EXCEPT); } int main() { // Set up FPE handler signal(SIGFPE, fpeHandler); printf("Demonstrating floating point exceptions\n"); // Enable FPE exceptions feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); // Division by zero printf("\nAttempting division by zero...\n"); float x = 1.0; float y = 0.0; float z = x / y; printf("Result: %f\n", z); // This may not execute printf("Program continuing...\n"); return 0; }

Best Practices and Pitfalls

1. Race Conditions

#include <stdio.h> #include <signal.h> #include <unistd.h> volatile sig_atomic_t flag = 0; void handler(int signum) { flag = 1; // Safe atomic assignment } int main() { signal(SIGUSR1, handler); // Correct pattern - no race printf("Waiting for signal (correct pattern)...\n"); while (!flag) { pause(); // Wait for signal } printf("Signal received!\n"); return 0; }

2. Reentrancy Issues

#include <stdio.h> #include <signal.h> #include <unistd.h> #include <stdlib.h> int globalVar = 0; void handler(int signum) { // BAD: Non-reentrant function // globalVar++; // Could be interrupted // GOOD: Atomic operation static volatile sig_atomic_t safe = 0; safe = 1; // Safe assignment } int main() { signal(SIGUSR1, handler); printf("Always use sig_atomic_t for shared variables\n"); return 0; }

3. Signal Handler Checklist

// ✅ DO: Use only async-signal-safe functions // ✅ DO: Use volatile sig_atomic_t for shared variables // ✅ DO: Keep handlers simple and fast // ✅ DO: Reset handlers if needed // ✅ DO: Save and restore errno // ❌ DON'T: Call non-reentrant functions (printf, malloc, free) // ❌ DON'T: Use global data structures without protection // ❌ DON'T: Assume signal ordering // ❌ DON'T: Ignore return values from signal functions // ❌ DON'T: Use longjmp in handlers (unless you know what you're doing)

Complete Practical Example

#include <stdio.h> #include <signal.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <errno.h> #define MAX_HANDLERS 10 typedef struct { int signum; int count; time_t lastTime; } SignalStats; SignalStats stats[MAX_HANDLERS]; int handlerCount = 0; // Signal-safe integer to string conversion void itoa_safe(int n, char *buf) { int i = 0; int isNegative = 0; if (n < 0) { isNegative = 1; n = -n; } do { buf[i++] = n % 10 + '0'; n /= 10; } while (n > 0); if (isNegative) { buf[i++] = '-'; } // Reverse string for (int j = 0; j < i / 2; j++) { char temp = buf[j]; buf[j] = buf[i - j - 1]; buf[i - j - 1] = temp; } buf[i] = '\0'; } // Generic signal handler void genericHandler(int signum) { int saved_errno = errno; // Update statistics for (int i = 0; i < handlerCount; i++) { if (stats[i].signum == signum) { stats[i].count++; stats[i].lastTime = time(NULL); break; } } // Write message using write() (async-signal-safe) const char *msg = "Signal received: "; write(STDOUT_FILENO, msg, strlen(msg)); char numBuf[16]; itoa_safe(signum, numBuf); write(STDOUT_FILENO, numBuf, strlen(numBuf)); write(STDOUT_FILENO, "\n", 1); errno = saved_errno; } // Register signal handler void registerSignal(int signum) { if (handlerCount < MAX_HANDLERS) { stats[handlerCount].signum = signum; stats[handlerCount].count = 0; stats[handlerCount].lastTime = 0; handlerCount++; signal(signum, genericHandler); printf("Registered handler for signal %d\n", signum); } } // Print statistics (not async-signal-safe - use in main loop) void printStats() { printf("\n=== Signal Statistics ===\n"); for (int i = 0; i < handlerCount; i++) { printf("Signal %d: %d times", stats[i].signum, stats[i].count); if (stats[i].lastTime > 0) { printf(" (last: %s", ctime(&stats[i].lastTime)); } else { printf("\n"); } } printf("========================\n"); } int main() { // Register various signals registerSignal(SIGINT); registerSignal(SIGTERM); registerSignal(SIGUSR1); registerSignal(SIGUSR2); registerSignal(SIGALRM); printf("\nSignal handler demo started. PID: %d\n", getpid()); printf("Available signals:\n"); printf(" Ctrl+C - SIGINT\n"); printf(" kill -TERM %d - SIGTERM\n", getpid()); printf(" kill -USR1 %d - SIGUSR1\n", getpid()); printf(" kill -USR2 %d - SIGUSR2\n", getpid()); printf(" kill -ALRM %d - SIGALRM\n\n", getpid()); // Set up timer alarm(5); // SIGALRM in 5 seconds // Main loop int running = 1; int iterations = 0; while (running) { printf("Working... (%d)\n", ++iterations); sleep(1); if (iterations >= 15) { running = 0; } // Print stats every 5 iterations if (iterations % 5 == 0) { printStats(); } } printStats(); printf("Program exiting normally\n"); return 0; }

Signal Handling Comparison

FunctionThread SafetyInformationPortabilityUse Case
signal()NoBasicPOSIX/UnixSimple handlers
sigaction()YesExtendedPOSIXAdvanced control
sigqueue()YesWith dataPOSIXReal-time signals
sigsuspend()N/AN/APOSIXAtomic waiting
sigaltstack()N/AN/APOSIXAlternate stack
sigprocmask()No (process)N/APOSIXSignal blocking

Conclusion

Signal handling is a powerful feature in C that allows programs to respond to asynchronous events:

Key Concepts

  • Signals are software interrupts for event notification
  • Default actions include terminate, ignore, core dump, stop
  • Custom handlers can override default behavior
  • sigaction() provides more control than signal()
  • Signal masks allow blocking/unblocking signals
  • Async-signal-safe functions are limited but essential

Best Practices

  1. Keep signal handlers simple and fast
  2. Use only async-signal-safe functions in handlers
  3. Use volatile sig_atomic_t for shared variables
  4. Block signals during critical sections
  5. Consider using sigaction() instead of signal()
  6. Test signal handling thoroughly

Common Applications

  • Graceful shutdown (SIGINT, SIGTERM)
  • Timer events (SIGALRM)
  • Child process monitoring (SIGCHLD)
  • User-defined communication (SIGUSR1, SIGUSR2)
  • Error recovery (SIGSEGV, SIGFPE)

Mastering signal handling is essential for writing robust system software, daemons, and applications that need to respond to external events or recover from errors gracefully.

Complete C Programming Guide + Compilers Collection


1. C srand() Function – Understanding Seed Initialization

https://macronepal.com/understanding-the-c-srand-function
Explains how srand() initializes the pseudo-random number generator in C by setting a seed value. Using the same seed produces the same sequence, while time(NULL) gives different results each run.


2. C rand() Function Mechanics and Limitations

https://macronepal.com/c-rand-function-mechanics-and-limitations
Explains how rand() generates pseudo-random numbers between 0 and RAND_MAX, its deterministic nature, and limitations for security use cases.


3. C log() Function

https://macronepal.com/c-log-function-2
Covers natural logarithm calculation using <math.h> and its applications.


4. Mastering Date and Time in C

https://macronepal.com/mastering-date-and-time-in-c
Explains <time.h> functions like time(), clock(), difftime(), and struct tm.


5. Mastering time_t Type in C

https://macronepal.com/mastering-the-c-time_t-type-for-time-management
Explains time representation as seconds since Unix epoch and conversion functions.


6. C exp() Function

https://macronepal.com/c-exp-function-mechanics-and-implementation
Explains exponential function exp(x) and its scientific applications.


7. C log() Function (Alternate Guide)

https://macronepal.com/c-log-function
Comparison of log() and log10() with usage examples.


8. C log10() Function

https://macronepal.com/mastering-the-log10-function-in-c
Explains base-10 logarithm for engineering and scientific applications.


9. C tan() Function

https://macronepal.com/understanding-the-c-tan-function
Explains tangent function and radian-based calculations.


10. Random Numbers in C (Secure vs Predictable)

https://macronepal.com/mastering-c-random-numbers-for-secure-and-predictable-applications
Explains difference between rand() and secure randomness methods.


11. Free Online C Compiler

https://macronepal.com/free-online-c-code-compiler-2
Browser-based compiler for testing C programs instantly.


C Functions, Arguments, Parameters & Flow

Mastering Functions in C – Complete Guide

https://macronepal.com/c/mastering-functions-in-c-a-complete-guide/
Covers function structure, modular programming, and real-world usage.


Function Arguments in C

https://macronepal.com/c-function-arguments/
Explains how arguments are passed and used in function calls.


Function Parameters in C

https://macronepal.com/c-function-parameters/
Explains defining inputs for functions and matching them with arguments.


Function Declarations in C

https://macronepal.com/c-function-declarations-syntax-rules-and-best-practices/
Covers prototypes, syntax rules, and best practices.


Function Calls in C

https://macronepal.com/understanding-function-calls-in-c-syntax-mechanics-and-best-practices/
Explains execution flow and parameter handling during function calls.


Void Functions in C

https://macronepal.com/understanding-void-functions-in-c-syntax-patterns-and-best-practices/
Explains functions that do not return values.


Return Values in C

https://macronepal.com/c-return-values-mechanics-types-and-best-practices/
Explains different return types and how functions return results.


Pass-by-Value in C

https://macronepal.com/aws/understanding-pass-by-value-in-c-mechanics-implications-and-best-practices/
Explains how copies of variables are passed into functions.


Pass-by-Reference in C

https://macronepal.com/c/understanding-pass-by-reference-in-c-pointers-semantics-and-safe-practices/
Explains using pointers to modify original variables.


C strstr() Function

https://macronepal.com/aws/c-strstr-function/
Explains substring search inside strings in C.


C Preprocessor & Macros

https://macronepal.com/mastering-c-variadic-macros-for-flexible-debugging/
https://macronepal.com/mastering-the-stdc-macro-in-c/
https://macronepal.com/c-time-macro-mechanics-and-usage/
https://macronepal.com/understanding-the-c-date-macro/
https://macronepal.com/c-file-type/
https://macronepal.com/mastering-c-line-macro-for-debugging-and-diagnostics/
https://macronepal.com/mastering-predefined-macros-in-c/
https://macronepal.com/c-error-directive-mechanics-and-usage/
https://macronepal.com/understanding-the-c-pragma-directive/
https://macronepal.com/c-include-directive/


C Structures, Memory, Scope & Linkage

https://macronepal.com/mastering-structures-in-c/
https://macronepal.com/c-structure-declaration-mechanics-and-usage/
https://macronepal.com/c-structure-initialization-mechanics-and-best-practices/
https://macronepal.com/mastering-c-structure-member-access-for-reliable-data-handling/
https://macronepal.com/c-nested-structures/
https://macronepal.com/mastering-arrays-of-structures-in-c/
https://macronepal.com/c-structure-pointers-mechanics-and-implementation/
https://macronepal.com/understanding-c-structure-parameter-passing-mechanics/
https://macronepal.com/mastering-c-returning-structures-for-efficient-data-flow/
https://macronepal.com/c-self-referential-structures/
https://macronepal.com/mastering-structure-alignment-in-c/
https://macronepal.com/c-structure-padding-mechanics-and-optimization/
https://macronepal.com/understanding-c-flexible-array-members-mechanics-and-usage/
https://macronepal.com/mastering-c-anonymous-structures-for-flattened-data-layouts/
https://macronepal.com/c-unions/
https://macronepal.com/mastering-c-name-mangling-and-symbol-decoration/
https://macronepal.com/c-no-linkage-mechanics-and-scope-isolation/
https://macronepal.com/understanding-c-internal-linkage-mechanics-and-architecture/


C Scope, Storage Classes & Typedef

https://macronepal.com/mastering-function-prototype-scope-in-c/
https://macronepal.com/c-function-scope-mechanics-and-visibility/
https://macronepal.com/understanding-c-file-scope-mechanics-and-architecture/
https://macronepal.com/mastering-c-scope-rules-for-predictable-name-resolution/
https://macronepal.com/c-scope-rules/
https://macronepal.com/mastering-c-register-storage-class-for-historical-context-and-modern-alternatives/
https://macronepal.com/mastering-_thread_local-in-c/
https://macronepal.com/c-extern-storage-class-mechanics-and-usage/
https://macronepal.com/understanding-the-c-static-storage-class-mechanics-and-usage/
https://macronepal.com/c-auto-storage-class/
https://macronepal.com/c-typedef-with-pointers/


Extra Articles

https://macronepal.com/13757-2/
https://macronepal.com/13748-2/
https://macronepal.com/13747-2/
https://macronepal.com/13746-2/
https://macronepal.com/13745-2/
https://macronepal.com/13708-2/
https://macronepal.com/13707-2/
https://macronepal.com/13702-2/


Online Compilers

https://macronepal.com/free-html-online-code-compiler/
https://macronepal.com/free-online-python-code-compiler/
https://macronepal.com/free-online-python2-code-compiler/
https://macronepal.com/free-online-java-code-compiler/
https://macronepal.com/free-online-javascript-code-compiler/
https://macronepal.com/free-online-node-js-code-compiler/
https://macronepal.com/free-online-c-code-compiler/
https://macronepal.com/free-online-c-code-compiler-2/
https://macronepal.com/free-online-c-code-compiler-3/
https://macronepal.com/free-online-php-code-compiler/
https://macronepal.com/free-online-ruby-code-compiler/
https://macronepal.com/free-online-perl-code-compiler/
https://macronepal.com/free-online-lua-code-compiler/
https://macronepal.com/free-online-tcl-code-compiler/
https://macronepal.com/free-online-groovy-code-compiler/
https://macronepal.com/free-online-j-shell-code-compiler/
https://macronepal.com/free-online-haskell-code-compiler/
https://macronepal.com/free-online-scala-code-compiler/
https://macronepal.com/free-online-common-lisp-code-compiler/
https://macronepal.com/free-online-d-code-compiler/
https://macronepal.com/free-online-ada-code-compiler/
https://macronepal.com/free-erlang-code-compiler/
https://macronepal.com/free-online-assembly-code-compiler/

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper