Keywords in C: Complete List, Usage & Examples
Conceptual Introduction & Fundamentals
What are Keywords?
In C, keywords are predefined tokens that the compiler interprets as instructions or declarations. They are part of the language specification and cannot be redefined or overloaded. For example, int, if, while, return, and struct are keywords.
Key characteristics:
- Reserved: You cannot use them as identifiers.
- Case-sensitive:
ifis a keyword, butIF,If, oriFare not (they are ordinary identifiers). - Standard-dependent: The set of keywords grows with each C standard revision.
- Purpose-specific: Keywords are categorized into data types, control flow, storage classes, type qualifiers, and more.
Why Keywords Matter
- They define the language’s grammar: control structures (
if,for), data types (int,char), and storage classes (static,extern). - They enable the compiler to parse code unambiguously. Using a keyword as an identifier leads to syntax errors.
- They allow programmers to express low-level concepts (e.g.,
volatile,register,sizeof) directly in source code.
Standard Versions and Keyword Count
- ANSI C (C89/C90): 32 keywords.
- C99: Adds
inline,restrict,_Bool,_Complex,_Imaginary. - C11: Adds
_Alignas,_Alignof,_Atomic,_Generic,_Noreturn,_Static_assert,_Thread_local. - C23: Further additions (e.g.,
constexpr,typeof,typeof_unqual,_BitInt).
For maximum portability, stick to the keywords defined by the standard you target (e.g., C99/C11) and avoid implementation-specific extensions.
Keywords vs. Identifiers
- Keywords are fixed by the language; you cannot create new ones.
- Identifiers are programmer-defined names that follow naming rules.
- A keyword cannot be used as an identifier, but an identifier can look like a keyword if the case is changed (e.g.,
Intis not a keyword).
Syntax & Core Mechanics
C keywords can be grouped into logical categories. Below is a detailed breakdown with examples.
Data Type Keywords
These declare variables or functions with specific types.
| Keyword | Usage |
|---|---|
char | Declares a character type (1 byte). |
int | Declares an integer type. |
float | Declares a single-precision floating-point type. |
double | Declares a double-precision floating-point type. |
void | Specifies no value (for functions with no return, or generic pointer). |
short | Modifies int to be at least 16 bits. |
long | Modifies int or double to be longer. |
signed | Explicitly declares a signed type. |
unsigned | Declares an unsigned type. |
_Bool | C99 boolean type (use stdbool.h for bool). |
_Complex | C99 complex number type (use complex.h). |
Example:
c
char grade = 'A'; int count = 10; float price = 19.99f; double preciseValue = 3.14159265358979; void printMessage(void); // function returning nothing short int small = 100; long int big = 100000L; unsigned int positive = 42; _Bool flag = 1; // C99 boolean
Control Flow Keywords
These control the execution order of statements.
| Keyword | Usage |
|---|---|
if | Executes a block if condition is true. |
else | Executes when if condition is false. |
switch | Selects one of many blocks based on an integer expression. |
case | Defines a branch within a switch. |
default | Executes when no case matches. |
for | Loop with initialization, condition, and increment. |
while | Loop while condition is true. |
do | Loop that executes at least once (with while). |
break | Exits the innermost loop or switch. |
continue | Skips the rest of the current loop iteration. |
goto | Transfers control to a labeled statement (use sparingly). |
return | Exits a function, optionally returning a value. |
Example:
c
#include <stdio.h> int main(void) { int x = 5; if (x > 0) { printf("Positive\n"); } else { printf("Non-positive\n"); } for (int i = 0; i < 3; i++) { if (i == 1) continue; // skip printing 1 printf("%d ", i); } printf("\n"); switch (x) { case 1: printf("One\n"); break; case 5: printf("Five\n"); break; default: printf("Other\n"); } return 0; } Expected output:
text
Positive 0 2 Five
Storage Class Keywords
These define the scope, lifetime, and storage location of variables.
| Keyword | Usage |
|---|---|
auto | Automatic storage (default for local variables). Rarely used explicitly. |
register | Suggests storing variable in a CPU register (compiler may ignore). |
static | Preserves variable value between function calls; internal linkage at file scope. |
extern | Declares a variable or function defined in another translation unit. |
Example:
c
#include <stdio.h> void counter(void) { static int count = 0; // static: retains value between calls count++; printf("Count: %d\n", count); } int globalVar = 100; // external linkage by default int main(void) { extern int globalVar; // refers to globalVar defined above counter(); counter(); return 0; } Expected output:
text
Count: 1 Count: 2
User-Defined Type Keywords
These allow creating custom data types.
| Keyword | Usage |
|---|---|
struct | Defines a structure (group of variables). |
union | Defines a union (same memory for different types). |
enum | Defines an enumeration (set of named integer constants). |
typedef | Creates an alias for an existing type. |
Example:
c
#include <stdio.h> typedef struct { int x; int y; } Point; enum Color { RED, GREEN, BLUE }; int main(void) { Point p = {10, 20}; enum Color c = GREEN; printf("Point: (%d,%d), Color: %d\n", p.x, p.y, c); return 0; } Expected output:
text
Point: (10,20), Color: 1
Qualifier Keywords
These modify the behavior of variables.
| Keyword | Usage |
|---|---|
const | Declares a read-only variable. |
volatile | Tells the compiler the variable may change unexpectedly (e.g., hardware registers). |
restrict | (C99) Promises exclusive access through a pointer, enabling optimization. |
Example:
c
const double PI = 3.14159; volatile int hardwareStatus; // could change outside program's control int * restrict ptr = malloc(sizeof(int)); // exclusive pointer
Memory Management and Utility Keywords
| Keyword | Usage |
|---|---|
sizeof | Returns the size of a type or object in bytes (compile-time operator). |
Example:
c
#include <stdio.h> int main(void) { int arr[10]; printf("Size of int: %zu\n", sizeof(int)); printf("Size of arr: %zu\n", sizeof(arr)); return 0; } Expected output (typical):
text
Size of int: 4 Size of arr: 40
Full Practical Code Example with Explanation
This program demonstrates the use of many C keywords in a coherent, real-world scenario: a simple inventory management system that reads product data, stores it in a structure, and provides a menu-driven interface using control flow and storage class keywords. It includes robust input handling and error checking.
Program: Inventory Manager
c
/** * inventory.c * Demonstrates use of C keywords: struct, typedef, enum, static, const, * if, else, switch, case, break, for, while, return, sizeof, etc. * Provides a menu to add and display products. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_PRODUCTS 100 #define MAX_NAME_LEN 50 /* Structure to represent a product */ typedef struct { char name[MAX_NAME_LEN]; int quantity; double price; } Product; /* Enumeration for menu options */ typedef enum { ADD_PRODUCT = 1, DISPLAY_PRODUCTS, EXIT_PROGRAM } MenuOption; /* Static global variable: product list and count */ static Product inventory[MAX_PRODUCTS]; static int productCount = 0; // static: internal linkage, retains value /* Function prototypes */ void addProduct(void); void displayProducts(void); int readInteger(const char *prompt); double readDouble(const char *prompt); int main(void) { int choice; const char *menuText = "\nInventory Menu:\n" "1. Add Product\n" "2. Display Products\n" "3. Exit\n" "Enter choice: "; while (1) { // infinite loop, terminated by 'break' in switch printf("%s", menuText); fflush(stdout); /* Read integer choice safely */ if (scanf("%d", &choice) != 1) { fprintf(stderr, "Invalid input. Exiting.\n"); break; } /* Clear input buffer to avoid leftover newline issues */ int c; while ((c = getchar()) != '\n' && c != EOF); switch (choice) { case ADD_PRODUCT: addProduct(); break; case DISPLAY_PRODUCTS: displayProducts(); break; case EXIT_PROGRAM: printf("Exiting program.\n"); return EXIT_SUCCESS; // return from main, terminates loop default: printf("Invalid option. Please try again.\n"); break; // break out of switch, continue loop } } return EXIT_SUCCESS; } /* Adds a product to the inventory */ void addProduct(void) { if (productCount >= MAX_PRODUCTS) { fprintf(stderr, "Inventory full. Cannot add more products.\n"); return; } Product newProduct; // automatic variable /* Read product name using fgets for safety */ printf("Enter product name: "); fflush(stdout); if (fgets(newProduct.name, MAX_NAME_LEN, stdin) == NULL) { fprintf(stderr, "Error reading name.\n"); return; } /* Remove trailing newline */ newProduct.name[strcspn(newProduct.name, "\n")] = '\0'; /* Read quantity */ newProduct.quantity = readInteger("Enter quantity: "); if (newProduct.quantity < 0) { fprintf(stderr, "Quantity cannot be negative.\n"); return; } /* Read price */ newProduct.price = readDouble("Enter price: "); if (newProduct.price < 0.0) { fprintf(stderr, "Price cannot be negative.\n"); return; } /* Store in static array */ inventory[productCount] = newProduct; productCount++; printf("Product added successfully.\n"); } /* Displays all products in inventory */ void displayProducts(void) { if (productCount == 0) { printf("No products to display.\n"); return; } printf("\n%-5s %-20s %-10s %-10s\n", "ID", "Name", "Qty", "Price"); for (int i = 0; i < productCount; i++) { printf("%-5d %-20s %-10d %-10.2f\n", i + 1, inventory[i].name, inventory[i].quantity, inventory[i].price); } } /* Helper: safely read an integer from stdin */ int readInteger(const char *prompt) { char buffer[32]; int value; char *endPtr; while (1) { printf("%s", prompt); fflush(stdout); if (fgets(buffer, sizeof(buffer), stdin) == NULL) { return -1; // signal error } value = (int)strtol(buffer, &endPtr, 10); if (endPtr == buffer || (*endPtr != '\n' && *endPtr != '\0')) { printf("Invalid integer. Please try again.\n"); continue; } return value; } } /* Helper: safely read a double from stdin */ double readDouble(const char *prompt) { char buffer[64]; double value; char *endPtr; while (1) { printf("%s", prompt); fflush(stdout); if (fgets(buffer, sizeof(buffer), stdin) == NULL) { return -1.0; // signal error } value = strtod(buffer, &endPtr); if (endPtr == buffer || (*endPtr != '\n' && *endPtr != '\0')) { printf("Invalid number. Please try again.\n"); continue; } return value; } } Explanation of Keywords Used
typedefcreates aliases:Productfor the structure,MenuOptionfor the enum.structdefines the product data type.enumdefines a set of named constants for menu choices.staticon globalinventoryandproductCountlimits their visibility to this file and preserves their values throughout program execution.constonmenuTextensures the string literal is not modified.while,for,switch,case,break,default,if,else,returncontrol program flow.sizeofis implicitly used in array declarations and buffer sizes.int,double,charare data type keywords.voidspecifies functions returning nothing.
Expected Output
Running the program and interacting:
text
Inventory Menu: 1. Add Product 2. Display Products 3. Exit Enter choice: 1 Enter product name: Laptop Enter quantity: 5 Enter price: 999.99 Product added successfully. Inventory Menu: 1. Add Product 2. Display Products 3. Exit Enter choice: 1 Enter product name: Mouse Enter quantity: 20 Enter price: 19.50 Product added successfully. Inventory Menu: 1. Add Product 2. Display Products 3. Exit Enter choice: 2 ID Name Qty Price 1 Laptop 5 999.99 2 Mouse 20 19.50 Inventory Menu: 1. Add Product 2. Display Products 3. Exit Enter choice: 3 Exiting program.
The program demonstrates safe input using fgets and strtol/strtod, robust error checking, and meaningful use of various keyword categories.
Common Pitfalls, Edge Cases & Memory Considerations
1. Using Keywords as Identifiers
The most obvious error: attempting to name a variable int, return, float, etc.
c
int float = 5; // Compilation error: expected identifier before 'float'
Solution: Always choose names that are not keywords. Check the keyword list for your target standard.
2. Case Sensitivity Confusion
C is case-sensitive. While is not while. Some programmers mistakenly write If or For, causing errors.
c
If (x > 0) { ... } // Error: 'If' undeclared identifier Solution: Use lowercase for keywords exactly as specified.
3. New Keywords in Later Standards
C99 introduced inline, restrict, _Bool, _Complex, _Imaginary. If you use these as identifiers in older compilers, they may compile fine, but code is not portable. Conversely, using them as keywords when compiling with C99+ will cause errors if used as variable names.
c
int restrict = 10; // Error in C99, but maybe OK in C89
Solution: Be aware of the C standard you are targeting. Use -std=c99, -std=c11, etc., and avoid using these reserved names.
4. Misusing Storage Class Keywords
registeris only a hint; modern compilers ignore it. Overusing it does not guarantee faster code.statichas two different meanings depending on context:- For local variables: static storage duration (retains value).
- For global variables/functions: internal linkage (visible only in that file).
Confusing these can lead to unintended behavior.
c
// file1.c static int hidden = 5; // only visible in file1.c // file2.c extern int hidden; // Link error: 'hidden' not defined externally
externdeclares a variable but does not define it. Forgetting the actual definition in some file leads to link errors.
5. const Does Not Make a Variable Constant at Runtime
const is a compile-time qualifier that prevents modification through that particular name, but the underlying memory may still be writable if cast away.
c
const int x = 10; int *p = (int*)&x; // Cast away const (not recommended) *p = 20; // Undefined behavior
Solution: Treat const as a promise, not an absolute guarantee. Use it for documentation and optimization, but do not rely on it for security.
6. volatile and Optimization
Without volatile, the compiler may optimize away repeated reads of a variable that appears unchanged. For memory-mapped hardware or signal handlers, this can cause bugs.
c
volatile int flag = 0; // In a loop, without volatile, compiler might assume flag never changes.
Solution: Use volatile for variables that can be modified externally (hardware, interrupts, threads).
7. sizeof is Not a Function
sizeof is an operator, often mistaken for a function. It can be used without parentheses for expressions.
c
int a; size_t s1 = sizeof a; // Valid size_t s2 = sizeof(a); // Also valid
But note: sizeof is evaluated at compile time (except for variable-length arrays in C99). Using it on an expression does not evaluate the expression.
8. Memory Considerations of Keywords
staticlocal variables are stored in the data segment (not stack), increasing memory footprint but avoiding stack overflow for large arrays.registermay reduce memory access but not actual memory usage.constvariables may be placed in read-only memory by the compiler, saving RAM and preventing accidental writes.volatileprevents certain optimizations but does not change memory location.restrictallows the compiler to perform aggressive optimizations by assuming no aliasing, potentially improving performance and reducing memory traffic.
9. Using goto Excessively
goto is a keyword but considered harmful if overused because it can create spaghetti code. However, it is sometimes useful for error handling in deeply nested loops.
c
for (...) { for (...) { if (error) goto cleanup; } } cleanup: free(resources); Use sparingly and only when it improves clarity.
Summary & Best Practices
C keywords are the fundamental building blocks of the language. They define types, control flow, storage, and qualifiers. Mastering their use is essential for writing efficient, portable, and maintainable code.
Key Takeaways
- Keywords are reserved; you cannot use them as identifiers.
- The set of keywords evolves with C standards (C89: 32, C99: +6, C11: +7, etc.).
- Keywords are case-sensitive; always use lowercase.
- Categories include data types, control flow, storage classes, user-defined types, qualifiers, and utility (
sizeof). - Understanding the exact meaning of each keyword (e.g.,
staticfor both storage duration and internal linkage) prevents bugs.
Best Practices
- Never attempt to use keywords as identifiers. Use descriptive names that are not reserved.
- Target a specific C standard and stick to its keyword set. Use
-std=c99or-std=c11to enforce. - Use
constliberally for variables that should not be modified; it improves readability and helps the optimizer. - Use
staticfor file-local functions and variables to hide implementation details and avoid name collisions. - Use
externonly for declarations in headers; define the variable in exactly one.cfile. - Avoid
register; it is obsolete and ignored by modern compilers. - Use
volatilefor hardware registers, signal handlers, and variables shared between threads. - Use
restrict(C99) in performance-critical code where you can guarantee no aliasing, but ensure correctness first. - Prefer structured control flow (
if,for,while,switch) overgoto. Usegotoonly for cleanup in error paths. - Be consistent with case and naming conventions to avoid confusion with keywords.
By mastering C keywords, you gain precise control over program behavior and lay a solid foundation for advanced systems programming.




