c - standard - o que são funções lambdas




func() vs func(vazio) em c99 (3)

void func() Na prática, um parâmetro vazio significa que qualquer argumento é aceito.

void func(void) não aceita argumento.

Mas no padrão C99, encontro essas linhas:

6.7.5.3 Declaradores de função (incluindo protótipos)
14 Uma lista de identificadores declara apenas os identificadores dos parâmetros da função. Uma lista vazia em um declarador de função que faz parte de uma definição dessa função especifica que a função não possui parâmetros. A lista vazia em um declarador de função que não faz parte de uma definição dessa função especifica que nenhuma informação sobre o número ou tipos de parâmetros é fornecida.

de acordo com o padrão, func() e func(void) são iguais?


de acordo com o padrão, func () e func (void) são iguais?

Não. func(void) diz que a função não aceita argumentos; enquanto que func() diz que a função recebe um número não especificado de argumentos. Ambos são válidos, mas o estilo func() é obsoleto e não deve ser usado.

Este é um artefato do pré-padrão C. C99 marcou isso como obsoleto.

6.11.6 Declaradores de função :

O uso de declaradores de função com parênteses vazios (não declaradores de tipo de parâmetro no formato de protótipo) é um recurso obsoleto.

A partir do C11, ele ainda permanece obsoleto e não foi removido do padrão.


TL; DR

Nas declarações,

void func1();     // obsolescent
void func2(void);

o comportamento é bem diferente. O primeiro declara uma função sem nenhum protótipo - e pode levar qualquer número de argumentos! Enquanto o último declara uma função com um protótipo, que não possui parâmetros e não aceita argumentos.

Nas definições

void func1() { }     // obsolescent

e

void func2(void) { }
  • O primeiro declara e define uma função func1 que não possui parâmetros nem protótipo

  • Este último declara e define uma função func2 com um protótipo que não possui parâmetros.

Esses dois se comportam de maneira distinta, enquanto o compilador C deve imprimir uma mensagem de diagnóstico ao chamar uma função prototipada com um número incorreto de argumentos, mas não precisa fazê-lo ao chamar uma função sem protótipo.

Ou seja, dadas as definições acima

func1(1, 2, 3); // need not produce a diagnostic message
func2(1, 2, 3); // must always produce a diagnostic message 
                // as it is a constraint violation

No entanto, ambas as chamadas são ilegais em programas estritamente conformes, pois são um comportamento explicitamente indefinido conforme 6.5.2.2p6 .

Além disso, os parênteses vazios são considerados uma característica obsoleta:

O uso de declaradores de função com parênteses vazios (não declaradores de tipo de parâmetro no formato de protótipo) é um recurso obsoleto.

e

O uso de definições de funções com identificadores de parâmetros separados e listas de declaração (não tipo de parâmetro no formato de protótipo e declaradores de identificador) é um recurso obsoleto.

Em detalhe

Existem 2 conceitos relacionados, mas distintos: parâmetros e argumentos.

  • argumentos são os valores passados ​​para a função

  • parâmetros são os nomes / variáveis ​​dentro da função que são configurados com os valores dos argumentos quando a função inserida

No seguinte trecho:

int foo(int n, char c) {
    ...
}

...

    foo(42, ch);

n e c são parâmetros. 42 e ch são argumentos.

O trecho citado refere-se apenas aos parâmetros de uma função, mas não menciona nada sobre o protótipo ou argumentos para a função.

A declaração void func1() significa que a função func1 pode ser chamada com qualquer número de argumentos , ou seja, nenhuma informação sobre o número de argumentos é especificada (como uma declaração separada, C99 especifica isso como "função sem especificação de parâmetro), enquanto o declaração void func2(void) significa que a função func2 não aceita nenhum argumento .

A citação na sua pergunta significa que, dentro de uma definição de função , void func1() e void func2(void) indicam a eles que não há parâmetros , ou seja , nomes de variáveis ​​que são configurados com os valores dos argumentos quando a função é inserida. O void func() {} contrasta com o void func(); o primeiro declara que func realmente não tem parâmetros, enquanto o último é uma declaração para uma função func para a qual nem parâmetros nem seus tipos são especificados (uma declaração sem protótipo).

No entanto, eles ainda diferem quanto à definição em

  • A definição void func1() {} não declara um protótipo, enquanto void func2(void) {} , porque () não é uma lista de tipos de parâmetros, enquanto (void) é uma lista de tipos de parâmetros ( 6.7.5.3.10 ):

    O caso especial de um parâmetro sem nome do tipo void como o único item na lista especifica que a função não possui parâmetros.

    e mais 6.9.1.7

    Se o declarador incluir uma lista de tipos de parâmetros, a lista também especificará os tipos de todos os parâmetros; esse declarador também serve como um protótipo de função para chamadas posteriores para a mesma função na mesma unidade de conversão. Se o declarador incluir uma lista de identificadores, os tipos dos parâmetros serão declarados na seguinte lista de declarações. Em qualquer um dos casos, o tipo de cada parâmetro é ajustado conforme descrito em 6.7.5.3 para uma lista de tipos de parâmetros; o tipo resultante deve ser um tipo de objeto.

    O declarador da definição de função para func1 não contém uma lista de tipos de parâmetros e, portanto, a função não possui um protótipo.

  • void func1() { ... } ainda pode ser chamado com qualquer número de argumentos, enquanto é um erro em tempo de compilação chamar void func2(void) { ... } com qualquer argumento (6.5.2.2):

    Se a expressão que denota a função chamada tiver um tipo que inclua um protótipo , o número de argumentos deverá concordar com o número de parâmetros. Cada argumento deve ter um tipo tal que seu valor possa ser atribuído a um objeto com a versão não qualificada do tipo de seu parâmetro correspondente.

    (ênfase minha)

    Essa é uma restrição que, de acordo com o padrão, diz que uma implementação em conformidade deve exibir pelo menos uma mensagem de diagnóstico sobre esse problema. Mas como o func1 não possui um protótipo, uma implementação em conformidade não é necessária para produzir nenhum diagnóstico.

No entanto, se o número de argumentos não for igual ao número de parâmetros, o comportamento será indefinido 6.5.2.2p6 :

Se a expressão que denota a função chamada possui um tipo que não inclui um protótipo , [...] Se o número de argumentos não for igual ao número de parâmetros, o comportamento será indefinido.

Portanto, em teoria, um compilador C99 em conformidade também pode errar ou diagnosticar um aviso neste caso. StoryTeller forneceu evidências de que o clang pode diagnosticar isso ; no entanto, meu GCC parece não fazer isso (e isso também pode ser necessário para que seja compatível com algum código obscuro antigo):

void test() { }

void test2(void) { }

int main(void) {
    test(1, 2);
    test2(1, 2);
}

Quando o programa acima é compilado com gcc -std=c99 test.c -Wall -Werror , a saída é:

test.c: In function main’:
test.c:7:5: error: too many arguments to function test2
     test2(1, 2);
     ^~~~~
test.c:3:6: note: declared here
 void test2(void) { }
      ^~~~~

Ou seja, os argumentos não são verificados em relação aos parâmetros de uma função cuja declaração na definição não é prototipada ( test ), enquanto o GCC considera um erro em tempo de compilação especificar quaisquer argumentos para uma função prototipada ( test2 ); qualquer implementação em conformidade deve diagnosticar isso, pois é uma violação de restrição.


A parte significativa da cotação está destacada em negrito abaixo:

6.7.5.3 Declaradores de funções (incluindo protótipos) 14 Uma lista de identificadores declara apenas os identificadores dos parâmetros da função. Uma lista vazia em um declarador de função que faz parte de uma definição dessa função especifica que a função não possui parâmetros. A lista vazia em um declarador de função que não faz parte de uma definição dessa função especifica que nenhuma informação sobre o número ou tipos de parâmetros é fornecida.

Portanto, quando a lista de parâmetros está vazia para uma função com seu corpo, elas são as mesmas. Mas disso é apenas uma declaração de uma função.

void function1(); // No information about arguments
void function2(void); // Function with zero arguments

void function3() {
    // Zero arguments
}

void function4(void) {
    // Zero arguments
}




c99