Sintaxe alternativa (K&R) C para declaração de função versus protótipos
Pergunta
O que é útil sobre isso C
Sintaxe - Usando declarações de função do estilo 'K&R'?
int func (p, p2)
void* p;
int p2;
{
return 0;
}
Consegui escrever isso no Visual Studios 2010beta
// yes, the arguments are flipped
void f()
{
void* v = 0;
func(5, v);
}
Não entendo. Qual é o objetivo desta sintaxe? Eu consigo escrever:
int func (p, p2)
int p2;
{
return 0;
}
// and write
int func (p, p2)
{
return 0;
}
A única coisa que parece especificar é quantos parâmetros ele usa e o tipo de retorno. Eu acho que parâmetros sem tipos são bem legais, mas por que permitir e o int paranName
Após o declarador da função? É estranho.
Também isso ainda é padrão C?
Solução
A pergunta que você está fazendo são realmente duas perguntas, não uma. A maioria das respostas até agora tentou cobrir a coisa toda com um cobertor genérico "This Is K&R Style", enquanto na verdade apenas uma pequena parte dela tem algo a ver com o que é conhecido como estilo K&R (a menos que você veja o idioma C inteiro como "K&R-Style" de uma maneira ou de outra :)
A primeira parte é a sintaxe estranha usada em função definição
int func(p, p2)
void *p;
int p2; /* <- optional in C89/90, but not in C99 */
{
return 0;
}
Este é na verdade uma definição de função no estilo K & R. Outra resposta cobriu isso muito bem. E não há muito, na verdade. A sintaxe é descontinuada, mas ainda é totalmente suportada mesmo em C99 (exceto "nenhuma regra implícita int" em C99, o que significa que em C99 você não pode omitir a declaração de p2
).
A segunda parte tem pouco a ver com o estilo K & R. Refiro -me ao fato de que a função pode ser chamada com argumentos "trocados", ou seja, nenhuma verificação do tipo de parâmetro ocorre nessa chamada. Isso tem muito pouco a ver com a definição no estilo K & R em si, mas tem tudo a ver com sua função sem protótipo. Veja, em C quando você declara uma função como esta
int foo();
na verdade declara uma função foo
isso leva um número não especificado de parâmetros do tipo desconhecido. Você pode chamá -lo como
foo(2, 3);
e como
j = foo(p, -3, "hello world");
Ans So So (você entendeu);
Somente a chamada com argumentos adequados "funcionará" (o que significa que os outros produzem comportamento indefinido), mas depende de você garantir sua correção. O compilador não é necessário para diagnosticar os incorretos, mesmo que de alguma forma conheça magicamente os tipos de parâmetros corretos e seu número total.
Na verdade, esse comportamento é um característica da linguagem C. Um perigoso, mas um recurso, no entanto. Permite que você faça algo assim
void foo(int i);
void bar(char *a, double b);
void baz(void);
int main()
{
void (*fn[])() = { foo, bar, baz };
fn[0](5);
fn[1]("abc", 1.0);
fn[2]();
}
ou seja, misture diferentes tipos de funções em uma matriz "polimórfica" sem timpastos (os tipos de funções variádicas não podem ser usadas aqui). Novamente, os perigos inerentes a essa técnica são bastante óbvios (não me lembro de ter usado, mas posso imaginar onde pode ser útil), mas isso é C afinal.
Finalmente, a parte que vincula a segunda parte da resposta ao primeiro. Quando você faz uma definição de função no estilo K&R, ela não apresenta um protótipo para a função. No que diz respeito ao tipo de função, seu func
Definição declara func
Como
int func();
ou seja, nem os tipos nem o número total de parâmetros são declarados. Na sua postagem original, você diz "... parece especificar é quantos parâmetros ele usa ...". Formalmente falando, não! Após o seu estilo K & R de dois parâmetros func
Definição que você ainda pode ligar func
Como
func(1, 2, 3, 4, "Hi!");
E não haverá nenhuma violação de restrição. (Normalmente, um compilador de qualidade lhe dará um aviso).
Além disso, um fato às vezes esquecido é que
int f()
{
return 0;
}
também é uma definição de função no estilo K & R que não introduz um protótipo. Para torná -lo "moderno", você teria que colocar um explícito void
na lista de parâmetros
int f(void)
{
return 0;
}
Finalmente, ao contrário de uma crença popular, as definições de função no estilo K & R e as declarações de função não prototipadas são totalmente suportadas no C99. O primeiro foi depreciado desde C89/90, se bem me lembro. C99 exige que a função seja declarada antes do primeiro uso, mas a declaração não é necessária para ser um protótipo. Aparentemente, a confusão decorre da confusão terminológica popular: muitas pessoas chamam qualquer declaração de função de "um protótipo", enquanto de fato "a declaração da função" não é a mesma coisa que "protótipo".
Outras dicas
Esta é uma sintaxe K&R C bastante antiga (pré-datas ANSI/ISO C). Atualmente, você não deve mais usá -lo (como já notou sua grande desvantagem: o compilador não verificará os tipos de argumentos para você). O tipo de argumento realmente padroniza para int
no seu exemplo.
Na época, essa sintaxe era usada, às vezes encontrava funções como
foo(p, q)
{
return q + p;
}
o que era realmente uma definição válida, como os tipos para foo
, p
, e q
padrão para int
.
Esta é simplesmente uma sintaxe antiga, que antecede a sintaxe "ANSI C" com a qual você pode estar mais familiarizado. É chamado "K&R C", normalmente.
Os compiladores suportam que ele seja completo e para poder lidar com as bases de código antigas, é claro.
Esta é a sintaxe K&R original antes de C ser padronizada em 1989. C89 Introduziu protótipos de função, emprestados de C ++, e depreciou a sintaxe de K&R. Não há razão para usá -lo (e muitas razões para não) no novo código.
Essa é uma relíquia de quando C não tinha protótipos para funções. Naquela época, (eu acho) as funções foram assumidas para retornar int
e todos os seus argumentos foram assumidos como serem int
. Não houve verificação feita nos parâmetros da função.
Você é muito melhor usando protótipos de função no idioma C atual.
E você devo Use -os em C99 (C89 ainda aceita a sintaxe antiga).
E C99 exige que as funções sejam declaradas (possivelmente sem um protótipo). Se você está escrevendo uma nova função do zero, precisará fornecer uma declaração ... faça um protótipo também: você não perde nada e obtém verificação extra do compilador.