Why C keywords are case sensitive?

6.4k views Asked by At

C keywords are predefined by the C compiler and they are lowercase in C89. Since there are only 32, why can't one define them as case-insensitive?

2

There are 2 answers

1
Rob Napier On BEST ANSWER

Because C is case-sensitive and those are the keywords. Making them case-insensitive would have made the compiler slower, but the real reason is that's how it was defined.

There was a lot of experimentation with letter case in the 60s. For a while, BCPL reserved lowercase words as system keywords to distinguish from user names, which had to be uppercase, or single-letter lowercase. But then they switched to uppercase (and later back to lowercase), and whether it was case sensitive depended on the compiler. Same was true for FORTRAN/Fortran, which generally isn't case sensitive at all, but sometimes is in wildly complicated ways.

So when I say "it would have made the compiler slower," I don't mean "because it's an older language and processor time was more precious." Most modern languages are case sensitive. Many older languages have varying amounts of case sensitivity over their history and implementations. But fundamentally case sensitivity is simpler for computers. It's how most of Unix is designed, and C (originally B) was built to be the system language for Unix. But again, this was just a particular design decision in Unix, not some "it must be this way" deep choice.

But all of this is just talking around and back-justifying the answer. The answer is: because that's how C is defined.

1
Petr Skocik On

You can:

https://ideone.com/Ebzf5J

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

char const * const kw[]={
"_Alignas",
"_Alignof",
"_Atomic",
"auto",
"_Bool",
"break",
"case",
"char",
"_Complex",
"const",
"continue",
"default",
"do",
"double",
"else",
"enum",
"extern",
"float",
"for",
"_Generic",
"goto",
"if",
"_Imaginary",
"inline",
"int",
"long",
"_Noreturn",
"register",
"restrict",
"return",
"short",
"signed",
"sizeof",
"static",
"_Static_assert",
"struct",
"switch",
"_Thread_local",
"typedef",
"union",
"unsigned",
"void",
"volatile",
"while",
};


static int comb(char * s, int ix, char const * orig){
    if(s[ix]==0){
        if(0!=strcmp(s,orig))
            return -(0>printf("#define %s %s\n", s, orig));
        return 0;
    }
    s[ix]=tolower(s[ix]);
    if(0>comb(s,ix+1,orig))
        return -1;
    s[ix]=toupper(s[ix]);
    if(0>comb(s,ix+1,orig))
        return -1;
    return 0; 
}
static int mk_defines(char const* s){
    char b[20];
    int len = strlen(s);
    memcpy(b,s,len+1);
    if(0>comb(b,0,s))
        return -1;
    return 0;
}

int main()
{
    int n = sizeof(kw)/sizeof(kw[0]);
    for(int i=0;i<n;i++){
        if(0>mk_defines(kw[i]))
            return -1;
    }
    return 0;
}

And it's only 29,694 defines (yea!).