¿Por qué el tamaño de una función en C es siempre de 1 byte?

87

Cuando verificamos el tamaño de una función usando sizeof(), siempre obtenemos 1 byte . ¿Qué significa este 1 byte?

usuario1645461
fuente

Respuestas:

80

Es una infracción de restricción y su compilador debería diagnosticarla. Si lo compila a pesar de eso, su programa tiene un comportamiento indefinido [gracias a @Steve Jessop por la aclaración del modo de falla, y vea la respuesta de @Michael Burr por qué algunos compiladores permiten esto]: De C11, 6.5.3.4./ 1:

El sizeofoperador no se aplicará a una expresión que tenga el tipo de función

Kerrek SB
fuente
11
Eso es una restricción, lo que significa que en un compilador conforme se diagnostica. Si el compilador lo compila de todos modos (habiéndolo diagnosticado), entonces el comportamiento no está definido. Si el compilador no lo diagnostica (lo que, por ejemplo, gcc no lo hace -pedantic), tiene un compilador no conforme y cada programa tiene un comportamiento indefinido.
Steve Jessop
1
El comportamiento lo coloca en la misma categoría que una extensión GNU C, pero no tengo idea de por qué alguien quiere ese comportamiento, así que no sé por qué los autores de GNU hicieron todo lo posible para agregarlo.
Steve Jessop
1
@SteveJessop: Tenga en cuenta que esto es incluso con -std=c11, no gnu11 . Esta es una extensión de compilador realmente extraña.
Kerrek SB
6
¡Oh! Apuesto a que es para habilitar la aritmética en los punteros de función, de la misma manera que sizeof(void)es 1 en GNU C.
Steve Jessop
3
Respecto a -std=c11: alguien debería referir las -std=c*opciones a los Estándares Publicitarios. No habilitan el modo de conformidad, simplemente deshabilitan las extensiones que evitarían la compilación de un programa bien formado (como typeofser una palabra clave, ya que un programa C bien formado puede usarlo como un nombre de variable, pero gccpor defecto rechazaría eso ). Para deshabilitar adicionalmente las extensiones que permiten que programas mal formados pasen sin ser diagnosticados, necesita -pedantico -pedantic-errors.
Steve Jessop
56

Este no es un comportamiento indefinido: el estándar del lenguaje C requiere un diagnóstico cuando se usa el sizeofoperador con un designador de función (un nombre de función), ya que es una violación de restricción para elsizeof operador.

Sin embargo, como una extensión del lenguaje C, GCC permite aritmética en voidpunteros y punteros de función, lo cual se hace tratando el tamaño de voiduna función como 1. Como consecuencia, el sizeofoperador evaluará 1para voido una función con GCC. Ver http://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html#Pointer-Arith

Puede hacer que GCC emita una advertencia al usar sizeofestos operandos usando las opciones -pedantico -Wpointer-arithpara GCC. O conviértalo en un error con -Werror=pointer-arith.

Michael Burr
fuente
Tu lógica es defectuosa. C requiere mensajes de diagnóstico para algunos UB, pero no para todos. No se puede afirmar que algo tiene un comportamiento definido solo porque hay un diagnóstico.
MSalters
4
C requiere un diagnóstico para todas las infracciones de restricciones (5.1.1.3 Diagnósticos en C99 o C11). Una restricción (3.8 en C99 / C11) es una "restricción, ya sea sintáctica o semántica, mediante la cual se debe interpretar la exposición de los elementos del lenguaje", que parece decir que algo que no sigue las restricciones no se puede interpretar .
Michael Burr
3
Y para ser claros: una infracción de restricción no da como resultado un comportamiento indefinido. Es un error, como un error de sintaxis. Por ejemplo, el estándar dice, "si se viola un requisito de" debe "o" no debe "que aparece fuera de una restricción , el comportamiento no está definido". Si una infracción de la restricción daría lugar a UB, ¿por qué la norma hablaría solo de los "debe" y "no debe" que no están en las restricciones aquí?
Michael Burr
3
Realmente no dije mucho sobre UB, excepto que sizeofuna función no es UB (que mencioné prácticamente solo porque otras respuestas indicaron que era UB). Pero tal vez lo confundí por la forma en que estructuré la oración. Para ser más claro. sizeofuna función no es UB (como han afirmado varias respuestas). Es una violación de la restricción. Como tal, requiere un diagnóstico. GCC lo permite como una extensión.
Michael Burr
2
@KerrekSB: el OP no recibe un diagnóstico porque presumiblemente están usando GCC, lo que permite este uso como una extensión del lenguaje C.
Michael Burr
13

Significa que el escritor del compilador decidió un valor de 1 en lugar de hacer que los demonios vuelen de su nariz (de hecho, fue otro uso indefinido de lo sizeofque nos dio esa expresión: "el compilador de C DEBE emitir un diagnóstico SI este es el primero requerido diagnóstico resultante de su programa, y ​​luego PUEDE hacer que los demonios salgan volando de su nariz (que, por cierto, bien podría SER el mensaje de diagnóstico documentado) al igual que PUEDE emitir diagnósticos adicionales para más violaciones de las reglas o restricciones de sintaxis (o, para el caso, por cualquier motivo que elija) ". https://groups.google.com/forum/?fromgroups=#!msg/comp.std.c/ycpVKxTZkgw/S2hHdTbv4d8J

A partir de esto, hay un término de jerga "demonios nasales" para cualquier cosa que un compilador decida hacer en respuesta a una construcción indefinida. 1es el demonio nasal de este compilador para este caso.

Jon Hanna
fuente
@IlmariKaronen Sin embargo, tendré que admitir que hay una razón por la que la mayoría de mis respuestas sobre C (y C ++) se basan en principios generales agnósticos del lenguaje o en nuggets históricos como ese. Mi experiencia C está al borde de lo histórico en sí mismo :)
Jon Hanna
7

Como otros señalaron, sizeof () puede tomar cualquier identificador válido, pero no devolverá un resultado válido (honestamente verdadero y válido) para los nombres de funciones. Además, definitivamente puede, o no, resultar en el síndrome de "demonios fuera de la nariz".

Si desea perfilar el tamaño de la función de su programa, verifique el mapa del enlazador, que se puede encontrar en el directorio de resultados intermedios (aquel donde se compilan las cosas en .obj / .o o donde se encuentra la imagen / ejecutable resultante). A veces hay una opción para generar o no este archivo de mapa ... depende del compilador / enlazador.

Si quisiera el tamaño de un puntero a una función, todos son del mismo tamaño, el tamaño de una palabra de direccionamiento en su CPU.

jpinto3912
fuente
1
¿Qué tipo de afirmación es "definitivamente puede o no puede"? ¿No es eso cierto de literalmente todo?
Kerrek SB
@KerrekSB sí, pero aquí puede o no hacer nada, y aún estar dentro de las reglas. Es cierto que un compilador puede o no negarse a compilar, int x = 1;pero solo uno de ellos está permitido para un compilador compatible con los estándares. Al sizeof()aplicarse a una función, puede devolver o no un valor establecido, o negarse a compilar, o devolver un valor aleatorio basado en lo que sea que esté en un registro particular en ese momento. Los demonios nasales literales son poco probables, pero dentro de la letra del estándar.
Jon Hanna
@kerrek Puede que no sea cierto para nada o puede que no sea falso para nada ... mírelo como algo poco lógico.
jpinto3912
1
Si desea saber el tamaño de un puntero a una función, aplíquelo sizeofa un puntero a una función.
alexis