What are C Keywords and Identifiers- C Programming Course Online

Need Help or More Information?

Questions about this free C programming course, embedded C training or career guidance? Get in touch.

C Keywords and Identifiers

Lecture 3 of the Elements of C chapter. Learn the reserved words of C, the rules for naming things, and the naming habits used in real embedded and Linux code. Part of our free embedded C programming course.

32
classic keywords
5
naming rules
4
runnable examples

Every word in a C program is one of two things: a keyword the language already owns, or an identifier you invented. Understanding C keywords and identifiers is the difference between writing code that merely compiles and writing code other engineers can read. In this lecture of our free embedded systems course you will learn the full keyword list grouped by purpose, the exact naming rules, which names are reserved even though they are not keywords, and the conventions followed in firmware and Linux kernel code.

Interviewers regularly ask why a name is invalid or whether main is a keyword. After this lecture you will answer with confidence.

What You Will Learn

  • What a keyword is, and the 32 classic keywords of C grouped by their job.
  • Keywords added by later standards such as C99, C11 and C23.
  • The five rules for writing a valid identifier and why C is case sensitive.
  • Reserved identifiers: names that are legal but dangerous.
  • Significant length of identifiers on old and modern compilers.
  • Practical naming conventions used in embedded C.

Prerequisites

  • The previous lectures on the character set and escape sequences (cp1_1 and cp1_2).
  • A C compiler such as GCC.

What Are C Keywords?

A keyword, also called a reserved word, is a word whose meaning is fixed by the language. The compiler recognises it during lexical analysis and treats it as part of the grammar. Because of that, you cannot reuse a keyword as the name of a variable, function or type. Keywords are always written in lowercase in the classic set, so while is a keyword but While and WHILE are ordinary names.

The 32 Classic C Keywords by Purpose

Instead of memorising an alphabetical list, learn them by what they do. Every keyword in the original 32 fits one of five groups.

GroupKeywordsJob
Basic and derived typeschar int float double void short long signed unsigned enum struct unionDescribe the kind of data and build new types
Storage classauto register static extern typedefControl lifetime, visibility and naming of declarations
Type qualifiersconst volatilePromise read-only use, or warn that a value can change unexpectedly
Control flowif else switch case default for while do break continue goto returnDecide what runs next
OperatorsizeofReports the size of a type or object at compile time

Count them: 12 in the first group, 5 in the second, 2 in the third, 12 in the fourth and 1 operator, giving 32.

Keyword map: where each of the 32 belongs
Types (12)charintfloatdoublevoidshortlongsignedunsignedenumstructunion
Storage (5)autoregisterstaticexterntypedef
Qualifiers (2)constvolatile
Control (12)ifelseswitchcasedefaultforwhiledobreakcontinuegotoreturn
Operator (1)sizeof

What Each Group Means in Practice

  • Types: char, int, float and double are the fundamental data types covered in lecture 4. short, long, signed and unsigned modify them. void means “no value” for functions or “unknown type” for pointers. struct groups different members, union overlays them in the same memory, and enum names a set of integer constants.
  • Storage class: static inside a function keeps a variable alive between calls; at file scope it hides a name from other files. extern declares something defined elsewhere. register is a hint to keep a variable in a CPU register, which modern compilers ignore. auto is the default for local variables and almost never written. typedef creates a new name for an existing type.
  • Qualifiers: const says the program will not modify an object through that name. volatile tells the compiler the value may change outside the program’s control, for example a hardware status register, so every access must really happen. Embedded engineers use volatile constantly.
  • Control flow: selection with if, else, switch, case, default; loops with for, while, do; jumps with break, continue, goto, return.
  • sizeof: an operator, not a function, which is why sizeof x works without parentheses.

Keywords Added After the Original 32

StandardNew keywords
C99inline restrict _Bool _Complex _Imaginary
C11_Alignas _Alignof _Atomic _Generic _Noreturn _Static_assert _Thread_local
C23bool true false nullptr constexpr typeof typeof_unqual alignas alignof static_assert thread_local and others

The early additions used an underscore plus capital letter on purpose: that namespace was already reserved, so old programs that happened to use words like bool as their own names did not break. C23 promotes the friendlier spellings to real keywords. Check which standard your toolchain defaults to with gcc -dM -E -x c /dev/null | grep __STDC_VERSION__.

C Identifiers: The Rules for Naming

An identifier is a name you give to a variable, function, array, structure, type, label or macro. The compiler enforces five rules.

Five rules checked in this order
Rule 1Only letters, digits and underscore may appear
Rule 2First character must be a letter or underscore, never a digit
Rule 3The name must not be a keyword
Rule 4Case matters: code, Code and CODE are different
Rule 5Only the first N characters are guaranteed significant

Valid and Invalid Identifier Examples

NameVerdictReason
net_payValidLetters and underscore
_dataValidStarts with underscore (but see reserved names below)
MARKSValidUppercase is allowed
rec1ValidDigit after the first position
IntValidDifferent from the keyword int because of case
5bcInvalidStarts with a digit
intInvalidKeyword
rec#InvalidThe hash is not allowed in a name
avg noInvalidA space would split it into two tokens

How Long Can an Identifier Be?

The language puts no upper limit on how long a name is, but compilers only promise to treat a certain number of leading characters as significant. Very old compilers looked at the first eight characters, so temperature1 and temperature2 could collide. The 1989 standard raised this to 31 characters, and C99 and C11 require at least 63 for names inside a file and 31 for external names the linker sees. Real toolchains today distinguish far more, but keeping names under about 30 characters is still sensible for readability and for portability to tiny vendor compilers.

Reserved Identifiers You Should Avoid

Some names are legal according to the five rules yet belong to the implementation:

  • Names starting with an underscore followed by an uppercase letter, such as _Count.
  • Names containing two consecutive underscores, such as my__var.
  • Names starting with a single underscore at file scope.
  • Names of standard library functions and macros, such as printf, malloc and NULL, when you would hide or redefine them.
  • Names starting with str, mem, is or to followed by a lowercase letter may be reserved for future library functions.

Not a keyword, still off limits: main, printf and NULL are not keywords, but redefining them leads to broken or undefined programs. Treat them as taken.

Naming Conventions in Embedded and Linux Code

ItemCommon styleExample
Variables and functionslowercase_with_underscoresread_sensor
Macros and constantsUPPERCASE_WITH_UNDERSCORESMAX_RETRIES
Enumeration valuesModule prefix, uppercaseGPIO_HIGH
Module-private functionsstatic plus a module prefixstatic void uart_flush(void)
Typedef namesSuffix such as _t (POSIX reserves this for itself, so use your own prefix)sensor_cfg_t

Module prefixes such as gpio_ or uart_ are an old trick that substitutes for namespaces, which C does not have. They keep names unique across a large code base and make search results easy to read.

Hands-On Examples: C Keywords and Identifiers

Example 1: An Identifier Validator

Goal: code the five rules yourself. The program tests ten names, including every valid and invalid sample from the table above.

#include <stdio.h>
#include <ctype.h>
#include <string.h>

static const char *kw[] = {
    "auto", "break", "case", "char", "const", "continue", "default", "do",
    "double", "else", "enum", "extern", "float", "for", "goto", "if", "int",
    "long", "register", "return", "short", "signed", "sizeof", "static",
    "struct", "switch", "typedef", "union", "unsigned", "void", "volatile",
    "while"
};

static int is_keyword(const char *s)
{
    for (size_t i = 0; i < sizeof kw / sizeof kw[0]; i++)
        if (strcmp(s, kw[i]) == 0)
            return 1;
    return 0;
}

static const char *check(const char *s)
{
    if (s[0] == '\0')
        return "empty name";
    if (!(isalpha((unsigned char)s[0]) || s[0] == '_'))
        return "must start with a letter or underscore";
    for (const char *p = s; *p != '\0'; p++)
        if (!(isalnum((unsigned char)*p) || *p == '_'))
            return "contains an illegal character";
    if (is_keyword(s))
        return "is a keyword";
    return "valid";
}

int main(void)
{
    const char *tests[] = { "net_pay", "_data", "MARKS", "rec1", "Int",
                            "5bc", "int", "rec#", "avg no", "while" };

    for (size_t i = 0; i < sizeof tests / sizeof tests[0]; i++)
        printf("%-8s -> %s\n", tests[i], check(tests[i]));
    return 0;
}
gcc -Wall -Wextra -std=c17 idcheck.c -o idcheck
./idcheck
net_pay  -> valid
_data    -> valid
MARKS    -> valid
rec1     -> valid
Int      -> valid
5bc      -> must start with a letter or underscore
int      -> is a keyword
rec#     -> contains an illegal character
avg no   -> contains an illegal character
while    -> is a keyword
  • The checks run in rule order: empty, first character, every character, then keyword lookup.
  • Int passes because the keyword comparison with strcmp is case sensitive.
  • avg no fails on the space, which is an illegal character in a name.
Try it yourself: add a rule for length

Add a check that rejects names longer than 31 characters with the message “too long for portable external names”. Use strlen and place the test before the keyword check.

Example 2: Case Sensitivity in Action

Goal: prove that names differing only by case are separate variables.

#include <stdio.h>

int main(void)
{
    int code = 1, Code = 2, CODE = 3;
    int Int = 9;                     /* legal: Int is not the keyword int */

    printf("code=%d Code=%d CODE=%d Int=%d\n", code, Code, CODE, Int);
    printf("sum = %d\n", code + Code + CODE + Int);
    return 0;
}
code=1 Code=2 CODE=3 Int=9
sum = 15
  • All four variables coexist: 1 + 2 + 3 + 9 equals 15.
  • This is legal but poor style. Names that differ only by case invite mistakes during code reviews.
Try it yourself: what if you rename Int to int?

The compiler stops with an error such as “expected identifier or ‘(‘”, because int is a keyword and cannot name a variable.

Example 3: One Program, Many Keywords

Goal: meet most of the keyword groups in one working program: types, storage class, qualifiers, control flow and sizeof.

#include <stdio.h>

enum level { LOW, MEDIUM, HIGH };
struct point { int x; int y; };
union num { int i; double d; };

static int next_id(void)
{
    static int id = 100;             /* keeps its value between calls */
    return ++id;
}

int main(void)
{
    const int limit = 3;
    volatile int flag = 1;
    unsigned int total = 0;
    typedef struct point Point;
    Point p = { 4, 7 };
    enum level lv = HIGH;
    union num n;
    long big = 100000L;
    short small = 7;
    signed char sc = -3;
    float f = 1.5f;
    int k = 0;

    n.d = 2.5;
    for (int i = 0; i < limit; i++) {
        if (i == 1)
            continue;
        total += (unsigned int)next_id();
    }

    switch (lv) {
    case LOW:  puts("level: LOW");  break;
    case HIGH: puts("level: HIGH"); break;
    default:   puts("level: other"); break;
    }

    while (flag) {
        flag = 0;
        k++;
    }
    do {
        k++;
    } while (k < 3);

    if (k == 3)
        goto done;
    puts("never printed");
done:
    printf("total=%u p=(%d,%d) n.d=%.1f\n", total, p.x, p.y, n.d);
    printf("big=%ld small=%d sc=%d f=%.1f k=%d\n", big, small, sc, f, k);
    printf("sizeof(union num)=%zu\n", sizeof(union num));
    return 0;
}
level: HIGH
total=203 p=(4,7) n.d=2.5
big=100000 small=7 sc=-3 f=1.5 k=3
sizeof(union num)=8
  • static int id inside next_id remembers its value, so the loop (which skips i == 1 through continue) calls it twice and adds 101 and 102, giving 203.
  • typedef struct point Point gives a shorter name; enum level gives named constants; union num stores an int or a double in the same 8 bytes.
  • The while loop runs once because flag is cleared; the do loop then runs until k reaches 3. The goto done jumps over a print statement; it is shown only to illustrate the keyword, not as a style recommendation.
  • const and volatile appear on the locals; on real hardware registers they would be paired as volatile uint32_t *.
Try it yourself: what happens if you remove static from id?

Each call starts again at 100, so both calls return 101 and the total becomes 202. That is the whole point of static inside a function.

Example 4: Naming Conventions in a GPIO Module

Goal: apply module prefixes, uppercase constants and static privacy to a small firmware-style module.

#include <stdio.h>

#define GPIO_PIN_COUNT 4

enum gpio_level { GPIO_LOW, GPIO_HIGH };

static enum gpio_level pin_state[GPIO_PIN_COUNT];

static void gpio_write(int pin_index, enum gpio_level level)
{
    pin_state[pin_index] = level;
}

static int gpio_count_high(void)
{
    int count = 0;
    for (int i = 0; i < GPIO_PIN_COUNT; i++)
        if (pin_state[i] == GPIO_HIGH)
            count++;
    return count;
}

int main(void)
{
    gpio_write(0, GPIO_HIGH);
    gpio_write(2, GPIO_HIGH);

    for (int i = 0; i < GPIO_PIN_COUNT; i++)
        printf("pin %d = %s\n", i, pin_state[i] == GPIO_HIGH ? "HIGH" : "LOW");
    printf("pins high: %d\n", gpio_count_high());
    return 0;
}
pin 0 = HIGH
pin 1 = LOW
pin 2 = HIGH
pin 3 = LOW
pins high: 2
  • Every public-looking name begins with gpio_ or GPIO_, so a search for that prefix finds all module code.
  • static on the array and functions keeps them private to this file, preventing name clashes at link time.
  • GPIO_PIN_COUNT is a macro in uppercase; changing it in one place resizes the array and both loops.
Try it yourself: add a gpio_toggle function

Write static void gpio_toggle(int pin_index) that flips between GPIO_LOW and GPIO_HIGH. Test it by toggling pin 1 twice and confirming that the count of high pins is unchanged afterwards.

Common Mistakes with C Keywords and Identifiers

MistakeResultFix
Naming a variable new, class or this and later compiling as C++Fails in C++, valid in CAvoid C++ keywords in shared headers
Starting a name with a digitSyntax errorPut a letter first: pin5, not 5pin
Leading underscore plus uppercaseSilent clash with compiler namesUse a plain prefix instead
Two names that differ only after 31 charactersLinker treats them as one on tiny toolchainsMake the difference early in the name
Forgetting volatile on hardware registersCompiler caches the value and skips real readsDeclare registers volatile
Shadowing a library name such as index or timeConfusing warnings or wrong callsChoose descriptive names

Best Practices, Performance and Security

  • Choose names that describe meaning, not type: retry_count beats i2.
  • Keep one naming style per project and follow the style guide of the code base you join; the Linux kernel documents its own.
  • Make everything private with static unless another file needs it.
  • Performance: identifier length has no runtime cost. Names are gone after compilation (except in debug symbols).
  • Security and safety: use const on data you do not intend to change; it turns accidental writes into compile errors and lets read-only data live in flash on a microcontroller.
  • Safety: volatile is for hardware and signal handlers, not a substitute for locks between threads.

Summary and Key Takeaways

  • C has 32 classic keywords; groups: types, storage class, qualifiers, control flow and sizeof. Later standards add more.
  • Keywords cannot be used as names; they are lowercase, so Int is a valid identifier.
  • Identifiers use letters, digits and underscore, must not start with a digit, are case sensitive, and must not be keywords.
  • Only the first 31 or so characters are guaranteed significant for external names.
  • Avoid reserved names: leading underscore with uppercase, double underscores, and standard library names.
  • Good embedded code uses prefixes, uppercase macros and static for privacy.

Quiz: C Keywords and Identifiers

Question 1

How many keywords are in the original C standard (C89)?

Show answer

32.

Question 2

Which of these is a valid identifier? A) 2fast B) _speed C) for D) my-var

Show answer

B. A starts with a digit, C is a keyword, D contains a hyphen.

Question 3

Is Return a keyword?

Show answer

No. Keywords are lowercase, so Return is an ordinary identifier.

Question 4

Which keyword makes a local variable keep its value between function calls?

Show answer

static.

Question 5

Is sizeof a function?

Show answer

No. It is a compile-time operator and a keyword.

Question 6

Name the two type qualifiers in C89.

Show answer

const and volatile.

Question 7

Why is _Total a bad variable name?

Show answer

An underscore followed by an uppercase letter is reserved for the implementation.

Question 8

Are code, Code and CODE the same variable?

Show answer

No. C is case sensitive, so they are three separate identifiers.

Interview Questions on Keywords and Identifiers

Q1. What does volatile do and when is it required?

Show answer

It forces the compiler to perform every read and write of the object as written, with no caching in registers and no elimination of apparently redundant accesses. It is required for memory-mapped hardware registers, variables modified by an interrupt handler or signal handler, and similar cases. It does not provide atomicity or ordering between threads.

Q2. Can a variable be both const and volatile?

Show answer

Yes. A read-only hardware status register is the classic case: your code must not write to it, yet its value changes on its own, so each read must happen.

Q3. What is the difference between static at file scope and static inside a function?

Show answer

At file scope it gives internal linkage: the name is invisible to other files. Inside a function it gives static storage duration: the variable lives for the whole program and keeps its value between calls, but its name is still local.

Q4. Is main a keyword?

Show answer

No. It is an ordinary identifier with special meaning to the startup code in a hosted environment. In a freestanding or bare-metal build the entry point may be named differently.

Q5. What does the register keyword do today?

Show answer

It is only a hint. Modern optimisers allocate registers better than humans, so it has almost no effect. Its one lasting rule is that you cannot take the address of a register variable.

Q6. Why might you use typedef with a struct?

Show answer

It removes the repeated struct keyword from declarations and lets you hide the representation behind an opaque name. Be aware that the Linux kernel style discourages typedefs for plain structures to keep code explicit.

Frequently Asked Questions

How many keywords does C have?

The classic C89 and C90 standards define 32. Later standards add more, so C23 has well over fifty when underscore-prefixed forms are counted.

What is the difference between a keyword and an identifier?

A keyword has a fixed meaning given by the language. An identifier is a name chosen by the programmer.

Can an identifier start with an underscore?

Yes, syntactically. In practice avoid it at file scope and never follow it with an uppercase letter or a second underscore.

Are C keywords case sensitive?

Yes. All keywords are lowercase in the classic set, and If or WHILE are normal names.

Why does C not allow spaces in names?

A space is a token separator, so the lexer would see two names. Use underscores or camel case.

Is this free embedded C course good for freshers?

Yes. It starts from zero and pairs each concept with tested examples, a quiz and interview questions, making it a free embedded systems course suitable for placement preparation.

Conclusion

Keywords are the fixed vocabulary of C and identifiers are the words you add. You now know how to sort the 32 classic keywords by purpose, validate a name using five concrete rules, avoid reserved identifiers, and follow naming conventions that make firmware readable. You also built a working identifier checker, which is an excellent small project to explain in an interview. Next in this free embedded C programming course we study data types and qualifiers: how big each type is, what range it holds, and why the same program can behave differently on different machines.

Next step

Extend the validator to read names from the keyboard and test it against your own variable names from earlier programs.

Need Help or More Information?

Questions about this free C programming course, embedded C training or career guidance? Get in touch.

2 Comments

Leave a Reply

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