Por que C usa o asterisco para ponteiros?
Simplesmente - porque B sim.
Como a memória é uma matriz linear, é possível interpretar o valor em uma célula como um índice nessa matriz, e o BCPL fornece um operador para essa finalidade. No idioma original, foi escrito rv
, e mais tarde !
, enquanto B usa o unário *
. Portanto, se p
é uma célula que contém o índice de (ou endereço de) ou o ponteiro para outra célula, *p
refere-se ao conteúdo da célula apontada, como um valor em uma expressão ou como o destino de uma atribuição.
Do desenvolvimento da linguagem C
É isso aí. Nesse ponto, a pergunta é tão desinteressante quanto "por que o python 3 usa .
para chamar um método? Por que não ->
?" Bem ... porque o Python 2 costuma .
chamar um método.
Raramente existe uma linguagem do nada. Ele tem influências e é baseado em algo que veio antes.
Então, por que B não usou !
para remover o ponteiro de um ponteiro como o seu BCPL predecessor?
Bem, o BCPL era um pouco prolixo. Em vez de &&
ou ||
BCPL usado logand
e logor
. Isso ocorreu porque a maioria dos teclados não possui teclas ∧
ou ∨
não é igual à palavra NEQV
(consulte o Manual de referência da BCPL ).
B parece ter sido parcialmente inspirado para reforçar a sintaxe, em vez de ter palavras longas para todos esses operadores lógicos que os programadores faziam com bastante frequência. E assim !
a desreferência se tornou *
para que !
pudesse ser usada para negação lógica. Observe que há uma diferença entre o *
operador unário e o *
operador binário (multiplicação).
Bem, e outras opções, como ->
?
O ->
foi levado para o açúcar sintático torno derefrences campo struct_pointer->field
que é(*struct_pointer).field
Outras opções como <-
poderiam criar análises ambíguas. Por exemplo:
foo <- bar
Isso deve ser lido como:
(foo) <- (bar)
ou
(foo) < (-bar)
É muito provável que criar um operador unário composto por um operador binário e outro operador unário tenha problemas, pois o segundo operador unário pode ser um prefixo para outra expressão.
Além disso, é novamente importante tentar reduzir ao mínimo as coisas que estão sendo digitadas. Eu odiaria ter que escrever:
int main(int argc, char->-> argv, char->-> envp)
Isso também se torna difícil de ler.
Outros caracteres podem ter sido possíveis ( @
não foram usados até o Objetivo C se apropriar ). Porém, novamente, isso vai para o núcleo de 'C usa *
porque B fez'. Por que B não usou @
? Bem, B não usou todos os personagens. Não havia nenhum bpp
programa (compare cpp ) e outros caracteres estavam disponíveis em B (como o #
que mais tarde foi usado pelo cpp).
Se posso arriscar um palpite sobre o porquê - é por causa de onde estão as chaves. De um manual em B :
Para facilitar a manipulação de endereços quando parecer aconselhável, B fornece dois operadores de endereço unário, *
e &
. &
é o operador de endereço, assim &x
como o endereço de x
, supondo que ele tenha um. *
é o operador indireto; *x
significa "use o conteúdo de x como endereço".
Observe que &
é o turno-7 e o *
turno-8. A proximidade entre eles pode ter sido uma dica para o programador sobre o que eles fazem ... mas isso é apenas um palpite. Alguém teria que perguntar a Ken Thompson sobre por que essa escolha foi feita.
Então, aí está. C é assim porque B era. B é assim porque queria mudar a forma como o BCPL era.
->
está sendo usado na linguagem C como um operador de desreferência - ao acessar campos em uma struct:,struct_pointer->field
que é a abreviação de(*struct_pointer).field
.