Por que o tamanho de uma função em C é sempre de 1 byte?

87

Quando verificamos o tamanho de uma função usando sizeof(), sempre obtemos 1 byte . O que significa este 1 byte?

user1645461
fonte

Respostas:

80

É uma violação de restrição e seu compilador deve diagnosticar isso. Se ele compilar apesar disso, seu programa tem comportamento indefinido [obrigado a @Steve Jessop pelo esclarecimento do modo de falha e veja a resposta de @Michael Burr para saber por que alguns compiladores permitem isso]: De C11, 6.5.3.4./ 1:

O sizeofoperador não deve ser aplicado a uma expressão que tenha tipo de função

Kerrek SB
fonte
11
Isso é uma restrição, o que significa que em um compilador em conformidade é diagnosticado. Se o compilador o compilar de qualquer maneira (depois de diagnosticar), o comportamento é indefinido. Se o compilador não o diagnosticar (o que por exemplo o gcc não faz sem -pedantic), você tem um compilador não conforme e cada programa tem um comportamento indefinido.
Steve Jessop
1
O comportamento o coloca na mesma categoria que uma extensão GNU C, mas não tenho ideia de por que alguém deseja esse comportamento, então não sei por que os autores do GNU se esforçaram para adicioná-lo.
Steve Jessop
1
@SteveJessop: Observe que isso é igual com -std=c11, não gnu11 . Esta é uma extensão de compilador realmente estranha.
Kerrek SB
6
Ooh! Aposto que é para habilitar a aritmética em ponteiros de função, da mesma forma que sizeof(void)é feito com 1 no GNU C.
Steve Jessop
3
A respeito -std=c11: alguém deve referir as -std=c*opções aos Padrões de Publicidade. Eles não habilitam o modo de conformidade, eles simplesmente desabilitam extensões que impediriam um programa bem formado de compilar (como typeofser uma palavra-chave, já que um programa C bem formado pode usá-lo como um nome de variável, mas gccpor padrão rejeitaria isso ) Para desativar adicionalmente as extensões que permitem que programas malformados passem sem diagnóstico, você precisa de -pedanticou -pedantic-errors.
Steve Jessop
56

Este não é um comportamento indefinido - o padrão da linguagem C requer um diagnóstico ao usar o sizeofoperador com um designador de função (um nome de função), pois é uma violação de restrição para o sizeofoperador.

No entanto, como uma extensão da linguagem C, o GCC permite aritmética em voidponteiros e ponteiros de função, o que é feito tratando o tamanho de uma voidou de uma função como 1. Como consequência, o sizeofoperador avaliará 1para voidou uma função com GCC. Consulte http://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html#Pointer-Arith

Você pode fazer com que o GCC emita um aviso ao usar sizeofcom esses operandos usando as opções -pedanticou -Wpointer-arithdo GCC. Ou cometa um erro com -Werror=pointer-arith.

Michael Burr
fonte
Sua lógica é falha. C requer mensagens de diagnóstico para alguns, mas não todos os UB. Você não pode afirmar que algo definiu o comportamento apenas porque há um diagnóstico.
MSalters
4
C requer um diagnóstico para todas as violações de restrição (5.1.1.3 Diagnóstico em C99 ou C11). Uma restrição (3.8 em C99 / C11) é uma "restrição, seja sintática ou semântica, pela qual a exposição dos elementos da linguagem deve ser interpretada", o que parece dizer que algo que não segue as restrições não pode ser interpretado .
Michael Burr
3
E para ser claro - uma violação de restrição não resulta em comportamento indefinido. É um erro, como um erro de sintaxe. Por exemplo, a norma diz: "se um" deve "ou" não deve "que aparece fora de uma restrição for violado, o comportamento é indefinido". Se uma violação de restrição resultasse em UB, por que o padrão falaria apenas sobre os "deve" e "não deve" que não estão nas restrições aqui?
Michael Burr
3
Eu realmente não disse nada sobre UB, exceto que sizeofuma função não é UB (que eu mencionei basicamente apenas porque outras respostas afirmaram que era UB). Mas talvez eu tenha confundido isso devido à maneira como estruturei a frase. Para ser mais claro. sizeofuma função não é UB (como várias respostas afirmam). É uma violação de restrição. Como tal, requer um diagnóstico. O GCC permite isso como uma extensão.
Michael Burr
2
@KerrekSB: o OP não obtém um diagnóstico porque presumivelmente eles estão usando o GCC, que permite esse uso como uma extensão da linguagem C.
Michael Burr
13

Isso significa que o redator do compilador decidiu por um valor de 1 ao invés de fazer demônios voarem de seu nariz (na verdade, foi outro uso indefinido sizeofque nos deu a expressão: "o próprio compilador C DEVE emitir um diagnóstico SE este for o primeiro exigido diagnóstico resultante de seu programa e, em seguida, PODE fazer com que demônios voem de seu nariz (o que, a propósito, poderia muito bem SER a mensagem de diagnóstico documentada), assim como PODE emitir diagnósticos adicionais para novas violações de regras ou restrições de sintaxe (ou, nesse caso, por qualquer motivo que desejar). " https://groups.google.com/forum/?fromgroups=#!msg/comp.std.c/ycpVKxTZkgw/S2hHdTbv4d8J

Disto existe a gíria "demônios nasais" para qualquer coisa que um compilador decida fazer em resposta a uma construção indefinida. 1é o demônio nasal deste compilador para este caso.

Jon Hanna
fonte
@IlmariKaronen Terei que admitir, porém, que há uma razão pela qual a maioria das minhas respostas em C (e C ++) são sobre princípios agnósticos de linguagem gerais ou pepitas históricas como essa. Minha experiência com C está beirando o histórico em si :)
Jon Hanna
7

Como outros apontaram, sizeof () pode receber qualquer identificador válido, mas não retornará um resultado válido (um honestamente verdadeiro e válido) para nomes de função. Além disso, pode ou não resultar na síndrome de "demônios saindo do nariz".

Se você quiser traçar o perfil do tamanho da função do seu programa, verifique o mapa do vinculador, que pode ser encontrado no diretório de resultados intermediário (aquele onde as coisas são compiladas em .obj / .o ou onde a imagem / executável resultante está). Às vezes há uma opção de gerar ou não este arquivo de mapa ... é dependente do compilador / vinculador.

Se você quiser o tamanho de um ponteiro para uma função, eles são todos do mesmo tamanho, o tamanho de uma palavra de endereçamento em sua cpu.

jpinto3912
fonte
1
Que tipo de declaração é "definitivamente pode ou não pode" ??? Isso não é verdade para literalmente tudo?
Kerrek SB
@KerrekSB sim, mas aqui ele pode ou não fazer nada, e ainda estar dentro das regras. É verdade que um compilador pode ou não se recusar a compilar, int x = 1;mas apenas um deles é permitido para um compilador compatível com os padrões. Ao sizeof()ser aplicada a uma função, ela pode ou não retornar um valor definido, ou se recusar a compilar, ou retornar um valor aleatório baseado no que quer que esteja em um determinado registro no momento. Demônios nasais literais são improváveis, mas dentro da letra do padrão.
Jon Hanna
@kerrek Pode ser verdade para nada ou pode não ser falso para nada ... olhe para isso como sendo ilógico difuso.
jpinto3912
1
Se você deseja saber o tamanho de um ponteiro para uma função, aplique sizeofa um ponteiro para uma função.
alexis