O que significa void em C, C ++ e C #?


170

Procurando entender os fundamentos de onde o termo " vazio " vem e por que ele é chamado de vazio. A intenção da pergunta é ajudar alguém que não tem experiência em C e, de repente, está olhando para uma base de código baseada em C.


2
Essa pergunta combina 3 idiomas ... essa pergunta herdada deve ser dividida em 3 perguntas diferentes.
Stargateur

Respostas:


225

Basicamente, significa "nada" ou "nenhum tipo"

Existem 3 maneiras básicas pelas quais o void é usado:

  1. Argumento da função: int myFunc(void) - a função não leva nada.

  2. Valor de retorno da função: void myFunc(int) - a função não retorna nada

  3. Ponteiro de dados genérico: void* data - 'data' é um ponteiro para dados de tipo desconhecido e não pode ser desreferenciado

Nota: o voidargumento em uma função é opcional em C ++, portanto, int myFunc()é exatamente o mesmo que int myFunc(void)e é deixado completamente de fora em C #. É sempre necessário para um valor de retorno.


7
vazio na lista de argumentos é opcional no C ++, consulte stackoverflow.com/questions/416345/...
Daniel Earwicker

1
Eu usaria "nenhum tipo" ao invés de "sem tamanho"
Kjetil Joergensen

@Earwicker e kjetijor, os dois pontos positivos em que debati, mas minha mente insone precisava de ajuda;) Obrigado.
Gerald

9
Não discordo, mas um uso adicional de nulo está no truque "lançar para anular" para suprimir avisos de valores não utilizados. É um pouco exagerado, pois não corresponde realmente à maneira como o compilador interpreta as coisas, mas você pode interpretar isso como "Estou usando esse valor para não fazer nada".
Steve Jessop

22
No C ++, o nulo na lista de argumentos é opcional. No entanto, em C, NÃO é opcional: foo () significa que aceita qualquer número de parâmetros de qualquer tipo, enquanto foo (vazio) significa que aceita zero parâmetros.
Adam Rosenfield

33

Eu sempre entendi isso como ausente . Aqui estão quatro casos na linguagem C que os jogos para este uso do ausente

  • R f(void)- Parâmetros de função ausentes
  • void f(P)- O valor de retorno está ausente
  • void *p- O tipo do que está apontado está ausente
  • (void) p- O uso do valor está ausente

Outros descendentes de C o usam para outras coisas. A Dlinguagem de programação o utiliza para casos em que um inicializador está ausente

  • T t = void;- valor inicial ausente

4
O que (void)pfaz? Não entendi bem o que você quis dizer com "o uso de valor está ausente".
Yashas 27/11

@Yashas Se alguém também está confuso sobre a (void) var;afirmação, encontrei respostas detalhadas em stackoverflow.com/q/21045615 .
Arnie97 22/05/19

14

Existem duas maneiras de usar o void:

void foo(void);

ou

void *bar(void*);

O primeiro indica que nenhum argumento está sendo passado ou que nenhum argumento está sendo retornado.

O segundo informa ao compilador que não há nenhum tipo associado aos dados, o que significa que você não pode usar os dados apontados até que sejam convertidos para um tipo conhecido.

Por exemplo, você verá void*muito uso quando tiver uma interface que chame uma função cujos parâmetros não possam ser conhecidos antecipadamente.

Por exemplo, no Kernel do Linux ao adiar o trabalho, você configurará uma função para ser executada posteriormente, fornecendo um ponteiro para a função a ser executada e um ponteiro para os dados a serem passados ​​para a função:

struct _deferred_work {
sruct list_head mylist;
.worker_func = bar;
.data        = somedata;
} deferred_work;

Em seguida, um thread do kernel passa por uma lista de trabalhos adiados e, quando chega a este nó, efetivamente executa:

bar(somedata);

Então no bar você tem:

void bar(void* mydata) {
    int *data = mydata;
    /* do something with data */;
}

13

Significa "sem valor". Você usa voidpara indicar que uma função não retorna um valor ou que não possui parâmetros ou ambos. Muito consistente com os usos típicos da palavra void em inglês.


4

Indica a ausência de um valor de retorno em uma função.

Alguns idiomas têm dois tipos de sub-rotinas: procedimentos e funções. Os procedimentos são apenas uma sequência de operações, enquanto uma função é uma sequência de operações que retornam um resultado.

Em C e seus derivados, a diferença entre os dois não é explícita. Tudo é basicamente uma função. a voidpalavra - chave indica que não é uma função "real", pois não retorna um valor.


3

Pense no vazio como a "estrutura vazia". Deixe-me explicar.

Toda função usa uma sequência de parâmetros, onde cada parâmetro tem um tipo. De fato, podemos empacotar os parâmetros em uma estrutura, com os slots de estrutura correspondentes aos parâmetros. Isso faz com que cada função tenha exatamente um argumento. Da mesma forma, funções produzem um resultado, que tem um tipo. Pode ser um booleano, ou pode ser flutuante, ou pode ser uma estrutura, contendo um conjunto arbitrário de outros valores digitados. Se queremos um idioma que tenha vários valores de retorno, é fácil insistir que eles sejam empacotados em uma estrutura. De fato, sempre poderíamos insistir que uma função retornasse uma estrutura. Agora toda função usa exatamente um argumento e produz exatamente um valor.

Agora, o que acontece quando eu preciso de uma função que produza um valor "não"? Bem, considere o que recebo quando forme uma estrutura com 3 slots: ela contém 3 valores. Quando tenho 2 slots, ele contém dois valores. Quando tem um slot, um valor. E quando tem zero slots, ele mantém ... uh, valores zero ou "no" value ". Então, posso pensar em uma função retornando nula como retornando uma estrutura que não contém valores. Você pode até decidir que" nula " é apenas um sinônimo para o tipo representado pela estrutura vazia, em vez de uma palavra-chave no idioma (talvez seja apenas um tipo predefinido :)

Da mesma forma, posso pensar em uma função que não requer valores como aceitar uma estrutura vazia, por exemplo, "void".

Eu posso até implementar minha linguagem de programação dessa maneira. A passagem de um valor nulo ocupa zero bytes, portanto, a passagem de valores nulos é apenas um caso especial de transmissão de outros valores de tamanho arbitrário. Isso facilita para o compilador tratar o resultado ou argumento "nulo". Você provavelmente deseja um recurso de linguagem que possa jogar fora um resultado de função; em C, se você chamar a função de resultado não nulo foo na seguinte instrução: foo (...); o compilador sabe que foo produz um resultado e simplesmente o ignora. Se nulo é um valor, isso funciona perfeitamente e agora "procedimentos" (que são apenas um adjetivo para uma função com resultado nulo) são apenas casos especiais triviais de funções gerais.

Void * é um pouco mais engraçado. Eu não acho que os designers de C pensaram em vazio da maneira acima; eles apenas criaram uma palavra-chave. Essa palavra-chave estava disponível quando alguém precisava de um ponto para um tipo arbitrário, portanto nulo * como o idioma em C. Na verdade, funciona muito bem se você interpretar nulo como uma estrutura vazia. Um ponteiro nulo * é o endereço de um local onde essa estrutura vazia foi colocada.

As transmissões de void * para T * para outros tipos T também funcionam com essa perspectiva. As conversões de ponteiro são um truque completo que funciona nas arquiteturas mais comuns para aproveitar o fato de que, se um tipo de composto T tiver um elemento com o subtipo S colocado fisicamente no início de T em seu layout de armazenamento, então converter S * para T * e vice-versa, usando o mesmo endereço físico da máquina tende a dar certo, já que a maioria dos ponteiros de máquinas tem uma única representação. Substituir o tipo S pelo tipo vazio dá exatamente o mesmo efeito e, assim, a conversão de / para vazio * funciona.

A linguagem de programação PARLANSE implementa as idéias acima de perto. Fizemos uma brincadeira em seu design e não prestamos muita atenção a "void" como um tipo de retorno e, portanto, temos palavras-chave de idioma para procedimento. Principalmente é apenas uma simples mudança de sintaxe, mas é uma das coisas que você não consegue quando obtém um grande código de funcionamento do corpo em um idioma.



2

Três casos de uso para nulo:

  1. Assinaturas de função. void foo(int bar)não retorna um valor. int bar(void)não tomar quaisquer parâmetros, mas isso geralmente é expressa com lista de argumentos vazio: int bar(). O uso da palavra-chave void aqui corresponde ao seu significado em inglês.

  2. Ponteiro genérico de tipo superior void *que aponta para dados não especificados e não pode ser desreferenciado. Aqui, o significado de vazio é diferente de outros significados de vazio: tipo universal vs. nenhum tipo.

  3. Em moldes que (void) new Foo(this)significam que o valor de retorno é deliberadamente jogado fora. Aqui, o uso da palavra-chave também corresponde ao seu significado em inglês.

Os casos 1 e 2 já foram cobertos pelo @Gerald, mas o caso 3 ainda não foi abordado.


2

Se você está explicando o conceito a um iniciante, pode ser útil usar uma analogia. O uso de nulo em todos esses casos é análogo ao significado de uma página de um livro que possui as seguintes palavras: "Esta página foi deixada intencionalmente em branco". É diferenciar para o compilador entre algo que deve ser sinalizado como erro, versus um tipo que é intencionalmente deixado em branco porque esse é o comportamento que você deseja.

Ele sempre aparece no código em que normalmente você esperaria ver um tipo aparecer, como um tipo de retorno ou um tipo de ponteiro. É por isso que, em C #, void mapeia para um tipo CLR real, System.Void, porque é um tipo em si.

Algumas linguagens de programação nunca desenvolveram o conceito de vazio, assim como algumas culturas humanas nunca inventaram o conceito de número zero. Vazio representa o mesmo avanço em uma linguagem de programação que o conceito de zero representa para a linguagem humana.


Apenas uma observação em relação à sua última frase - lembre-se de que só é verdade para idiomas com tipos estatísticos. Linguagens dinamicamente tipadas não precisam de nulo, pois seus métodos simplesmente não retornam nada - o "nulo" está implícito na falta de qualquer outra coisa sendo retornada.
Mark Embling

Correção no meu último comentário - eu quis dizer o último parágrafo (não a frase).
59868 Mark Embling

1

Significa "sem valor". Você usa void para indicar que uma função não retorna um valor ou que não possui parâmetros ou ambos. É muito consistente com os usos típicos da palavra void em inglês.

Nulo não deve ser confundido com nulo. Nulo significa que para a variável cujo endereço está na pilha, o valor no heap para esse endereço está vazio.


0

Vazio é usado apenas em assinaturas de método. Para tipos de retorno, significa que o método não retornará nada ao código de chamada. Para parâmetros, significa que nenhum parâmetro é passado para o método

por exemplo

void MethodThatReturnsAndTakesVoid(void)
{
// Method body
}

Em C #, podemos omitir o vazio para parâmetros e escrever o código acima como:

void MethodThatReturnsAndTakesVoid()
{
// Method body
}

Nulo não deve ser confundido com nulo. Nulo significa que para a variável cujo endereço está na pilha, o valor no heap para esse endereço está vazio.


0

Vazio é um tipo incompleto que, por definição, não pode ser um valor l. Isso significa que não é possível obter um valor atribuído.

Portanto, também não pode conter nenhum valor.


-1

void significa que você não retornará nenhum valor da função ou método


-1

Anular significa nenhum valor necessário no tipo de retorno de uma função nos três idiomas.


-1

Vazio é o equivalente ao Sub do Visual Basic.


Somente como um tipo de retorno. Eu posso pensar em mais três usos do void: argumentos void (a função não leva nada), ponteiros void (nenhum tipo de ponteiro especificado) e conjurações void (valor descartado).
C4757p
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.