Colchetes []
são mais fáceis de escrever, desde IBM 2741 terminal que foi "amplamente utilizado em Multics" OS, que por sua vez tinha Dennis Ritchie, um dos criadores da linguagem C como membro da equipe dev .
Observe a ausência de chaves no layout do IBM 2741!
Em C, chaves entre colchetes são "tiradas", pois são usadas para matrizes e ponteiros . Se os projetistas de linguagem esperassem que matrizes e ponteiros fossem mais importantes / usados com mais freqüência do que blocos de código (o que soa como uma suposição razoável ao seu lado, mais no contexto histórico do estilo de codificação abaixo), isso significaria que chaves entre chaves seriam "menos importantes" "sintaxe.
A importância das matrizes é bastante aparente no artigo O desenvolvimento da linguagem C de Ritchie. Existe até uma suposição explicitamente declarada de "prevalência de indicadores em programas C" .
... nova linguagem retinha uma explicação coerente e viável (se não usual) da semântica de matrizes ... Duas idéias são as mais características de C entre os idiomas de sua classe: a relação entre matrizes e ponteiros ... A outra característica de C, seu tratamento de matrizes ... tem virtudes reais . Embora a relação entre ponteiros e matrizes seja incomum, ela pode ser aprendida. Além disso, a linguagem mostra um poder considerável para descrever conceitos importantes, por exemplo, vetores cuja duração varia em tempo de execução, com apenas algumas regras e convenções básicas ...
Para uma melhor compreensão do contexto histórico e do estilo de codificação da época em que a linguagem C foi criada, é necessário levar em consideração que "a origem de C está intimamente ligada ao desenvolvimento do Unix" e, especificamente, que portar o SO para um PDP- 11 "levou ao desenvolvimento de uma versão inicial do C" ( fonte de citações ). Segundo a Wikipedia , "em 1972, o Unix foi reescrito na linguagem de programação C" .
O código fonte de várias versões antigas do Unix está disponível online, por exemplo, no site da árvore Unix . Das várias versões apresentadas lá, a mais relevante parece ser a Segunda Edição Unix, datada de 1972-06:
A segunda edição do Unix foi desenvolvida para o PDP-11 no Bell Labs por Ken Thompson, Dennis Ritchie e outros. Ele estendeu a Primeira Edição com mais chamadas do sistema e mais comandos. Esta edição também viu o início da linguagem C, que foi usada para escrever alguns dos comandos ...
Você pode procurar e estudar o código fonte C na página Second Edition Unix (V2) para ter uma idéia do estilo de codificação típico da época.
Um exemplo proeminente que apóia a idéia de que naquela época era bastante importante que o programador pudesse digitar colchetes com facilidade pode ser encontrado no código-fonte V2 / c / ncc.c :
/* C command */
main(argc, argv)
char argv[][]; {
extern callsys, printf, unlink, link, nodup;
extern getsuf, setsuf, copy;
extern tsp;
extern tmp0, tmp1, tmp2, tmp3;
char tmp0[], tmp1[], tmp2[], tmp3[];
char glotch[100][], clist[50][], llist[50][], ts[500];
char tsp[], av[50][], t[];
auto nc, nl, cflag, i, j, c;
tmp0 = tmp1 = tmp2 = tmp3 = "//";
tsp = ts;
i = nc = nl = cflag = 0;
while(++i < argc) {
if(*argv[i] == '-' & argv[i][1]=='c')
cflag++;
else {
t = copy(argv[i]);
if((c=getsuf(t))=='c') {
clist[nc++] = t;
llist[nl++] = setsuf(copy(t));
} else {
if (nodup(llist, t))
llist[nl++] = t;
}
}
}
if(nc==0)
goto nocom;
tmp0 = copy("/tmp/ctm0a");
while((c=open(tmp0, 0))>=0) {
close(c);
tmp0[9]++;
}
while((creat(tmp0, 012))<0)
tmp0[9]++;
intr(delfil);
(tmp1 = copy(tmp0))[8] = '1';
(tmp2 = copy(tmp0))[8] = '2';
(tmp3 = copy(tmp0))[8] = '3';
i = 0;
while(i<nc) {
if (nc>1)
printf("%s:\n", clist[i]);
av[0] = "c0";
av[1] = clist[i];
av[2] = tmp1;
av[3] = tmp2;
av[4] = 0;
if (callsys("/usr/lib/c0", av)) {
cflag++;
goto loop;
}
av[0] = "c1";
av[1] = tmp1;
av[2] = tmp2;
av[3] = tmp3;
av[4] = 0;
if(callsys("/usr/lib/c1", av)) {
cflag++;
goto loop;
}
av[0] = "as";
av[1] = "-";
av[2] = tmp3;
av[3] = 0;
callsys("/bin/as", av);
t = setsuf(clist[i]);
unlink(t);
if(link("a.out", t) | unlink("a.out")) {
printf("move failed: %s\n", t);
cflag++;
}
loop:;
i++;
}
nocom:
if (cflag==0 & nl!=0) {
i = 0;
av[0] = "ld";
av[1] = "/usr/lib/crt0.o";
j = 2;
while(i<nl)
av[j++] = llist[i++];
av[j++] = "-lc";
av[j++] = "-l";
av[j++] = 0;
callsys("/bin/ld", av);
}
delfil:
dexit();
}
dexit()
{
extern tmp0, tmp1, tmp2, tmp3;
unlink(tmp1);
unlink(tmp2);
unlink(tmp3);
unlink(tmp0);
exit();
}
getsuf(s)
char s[];
{
extern exit, printf;
auto c;
char t, os[];
c = 0;
os = s;
while(t = *s++)
if (t=='/')
c = 0;
else
c++;
s =- 3;
if (c<=8 & c>2 & *s++=='.' & *s=='c')
return('c');
return(0);
}
setsuf(s)
char s[];
{
char os[];
os = s;
while(*s++);
s[-2] = 'o';
return(os);
}
callsys(f, v)
char f[], v[][]; {
extern fork, execv, wait, printf;
auto t, status;
if ((t=fork())==0) {
execv(f, v);
printf("Can't find %s\n", f);
exit(1);
} else
if (t == -1) {
printf("Try again\n");
return(1);
}
while(t!=wait(&status));
if ((t=(status&0377)) != 0) {
if (t!=9) /* interrupt */
printf("Fatal error in %s\n", f);
dexit();
}
return((status>>8) & 0377);
}
copy(s)
char s[]; {
extern tsp;
char tsp[], otsp[];
otsp = tsp;
while(*tsp++ = *s++);
return(otsp);
}
nodup(l, s)
char l[][], s[]; {
char t[], os[], c;
os = s;
while(t = *l++) {
s = os;
while(c = *s++)
if (c != *t++) goto ll;
if (*t++ == '\0') return (0);
ll:;
}
return(1);
}
tsp;
tmp0;
tmp1;
tmp2;
tmp3;
É interessante observar como a motivação pragmática de escolher caracteres para denotar elementos de sintaxe da linguagem com base em seu uso em aplicações práticas direcionadas se assemelha à Lei de Zipf, conforme explicado nesta resposta fantástica ...
A relação observada entre frequência e duração é chamada Lei de Zipf
... com a única diferença de que o comprimento na instrução acima é substituído por / generalizado como velocidade de digitação.