Los corchetes []
son más fáciles de escribir, desde el terminal IBM 2741 que fue "ampliamente utilizado en el sistema operativo Multics" , que a su vez tenía a Dennis Ritchie, uno de los creadores del lenguaje C como miembro del equipo de desarrollo .
¡Tenga en cuenta la ausencia de llaves en el diseño de IBM 2741!
En C, los "corchetes" se "toman", ya que se usan para matrices y punteros . Si los diseñadores de lenguaje esperaran que las matrices y los punteros fueran más importantes / utilizados con más frecuencia que los bloques de código (lo que parece una suposición razonable a su lado, más sobre el contexto histórico del estilo de codificación a continuación), eso significaría que las llaves se irían a "menos importantes "sintaxis.
La importancia de las matrices es bastante evidente en el artículo El desarrollo del lenguaje C de Ritchie. Incluso hay una suposición explícitamente establecida de "prevalencia de punteros en los programas en C" .
... el nuevo lenguaje retuvo una explicación coherente y viable (si es inusual) de la semántica de las matrices ... Dos ideas son las más características de C entre los lenguajes de su clase: la relación entre matrices y punteros ... La otra característica de C, su tratamiento de matrices ... tiene virtudes reales . Aunque la relación entre punteros y matrices es inusual, se puede aprender. Además, el lenguaje muestra un poder considerable para describir conceptos importantes, por ejemplo, vectores cuya longitud varía en el tiempo de ejecución, con solo unas pocas reglas y convenciones básicas ...
Para una mejor comprensión del contexto histórico y el estilo de codificación de la época en que se creó el lenguaje C, uno debe tener en cuenta que "el origen de C está estrechamente relacionado con el desarrollo de Unix" y, específicamente, que portar el sistema operativo a un PDP- 11 "condujo al desarrollo de una versión temprana de C" ( fuente de citas ). Según Wikipedia , "en 1972, Unix fue reescrito en el lenguaje de programación C" .
El código fuente de varias versiones antiguas de Unix está disponible en línea, por ejemplo, en el sitio The Unix Tree . De varias versiones presentadas allí, la más relevante parece ser la Segunda Edición de Unix con fecha de 1972-06:
La segunda edición de Unix fue desarrollada para el PDP-11 en Bell Labs por Ken Thompson, Dennis Ritchie y otros. Extendió la Primera Edición con más llamadas al sistema y más comandos. Esta edición también vio el comienzo del lenguaje C, que se utilizó para escribir algunos de los comandos ...
Puede explorar y estudiar el código fuente C desde la página Unix (V2) de la Segunda Edición para tener una idea del estilo de codificación típico de la época.
Un ejemplo destacado que respalda la idea de que en aquel entonces era bastante importante para el programador poder escribir corchetes con facilidad se puede encontrar en el código fuente 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;
Es interesante observar cómo la motivación pragmática de elegir personajes para denotar elementos de sintaxis del lenguaje en función de su uso en aplicaciones prácticas específicas se asemeja a la Ley de Zipf como se explica en esta excelente respuesta ...
La relación observada entre frecuencia y longitud se llama Ley de Zipf
... con la única diferencia de que la longitud en la declaración anterior se sustituye por / generalizada como velocidad de escritura.