Si hallas algún error en tu código o trabajo, recuerda probar siempre en un ambiente de testing antes subir el código al trabajo final.
Solución:
¿Cuál es la diferencia entre una función de biblioteca y una función incorporada?
Una función incorporada es aquella de la que el compilador tiene cierto conocimiento directamente dentro del propio compilador. Una función de biblioteca es simplemente una función definida en una biblioteca. Pueden existir una función integrada y una función de biblioteca con el mismo nombre, por lo que para el resto de sus preguntas, trataré la “función de biblioteca” como “función de biblioteca que no es una función integrada”.
¿Hay algo que pueda hacer una función integrada pero que no pueda hacer una función de biblioteca?
Sí. Una función integrada puede elegir, por ejemplo, no evaluar sus argumentos:
int main()
int i = 0;
__builtin_constant_p (++i); // checks whether ++i is a constant expression
// does not evaluate ++i
return i; // returns 0
Esto se debe a que el compilador puede transformar una función integrada en otra cosa, que en realidad no necesita contener ninguna llamada de función.
¿Puedo escribir una función de biblioteca que realice la misma tarea que la función incorporada printf?
Hay algún conocimiento incorporado de printf
, pero en su mayor parte, esto es perfectamente factible. Busque cómo usar
.
¿Cómo puedo saber el tipo de los parámetros de entrada (%f, float o double)?
Tienes que confiar en la persona que llama para dejar que el formato string hacer coincidir los argumentos restantes; usted no puede detectar algo como pasar un int
cuando el formato string espera un double
. Pero no es necesario manejar la diferencia entre float
y double
porque es imposible pasar un float
para printf
: se convertirá en double
(independientemente del formato string) antes de printf
lo ve. Los requisitos de printf
se han hecho cuidadosamente para evitar cualquier necesidad de magia de compilación.
Las instrucciones de máquina de las funciones incorporadas de GCC no se almacenan en una biblioteca, ¿verdad?
Las llamadas a funciones integradas se transforman en tiempo de compilación, pero esa transformación puede resultar simplemente en una llamada a una función de biblioteca del mismo nombre.
¿Dónde están?
Si la transformación se realiza en tiempo de compilación, no hay instrucciones de máquina. La llamada se transforma en un código diferente, y ese código luego se compila para producir instrucciones de máquina. Si el resultado es una llamada a una función de biblioteca, las instrucciones de máquina para esa función de biblioteca son parte de la biblioteca.
Al vincular, ¿cómo puede controlar dónde colocar estos códigos de función incorporados?
No entiendo lo que quieres decir aquí. Una llamada a una función integrada se transforma en tiempo de compilación en un código diferente, y ese código diferente luego se compila como parte de la función que contiene la llamada. Se colocará donde se colocará el resto del código de esa función contenedora.
¿Por qué a veces puedo mostrar mensajes de error como “referencia indefinida a __builtin_stdarg_start” al vincular
No hay una función incorporada __builtin_stdarg_start
a pesar de la __builtin
prefix, por lo que esto se trata como una llamada a una función de biblioteca. Y no hay función de biblioteca. __builtin_stdarg_start
tampoco, por lo que el enlazador detecta esto como un error.
Solía haber una función incorporada __builtin_stdarg_start
pero se eliminó hace años, y el código nunca debería haberlo usado en primer lugar.
gcc -c main.c, nm muestra que no hay ningún símbolo printf en main.o, (solo main(T) y puts(U)), ¿por qué?
Eso es porque printf
existe como función integrada y como función de biblioteca. La función incorporada generalmente simplemente llama a la función de biblioteca, pero a veces es posible hacerlo mejor, incluso en su ejemplo. En este caso, la función integrada printf
puede dar el resultado correcto sin llamar a la función de biblioteca printf
.
Hay aproximadamente dos tipos de funciones integradas: las que corresponden a funciones de biblioteca estándar (malloc
, printf
y strcpy
todos se tratan como integrados de forma predeterminada), y los que no tienen una contraparte en la biblioteca estándar, piense en __builtin_expect
, __builtin_prefetch
etc.
El primer tipo de integrados está ahí para permitir que el compilador emita código optimizado en lugar de las llamadas correspondientes. Conociendo la semántica interna de cada una de las llamadas de la biblioteca estándar, el compilador puede decidir emitir una llamada a la función que reside en la biblioteca o emitir una pieza de código generada a medida en su lugar, de modo que la semántica original se conservan y el código se ejecuta mejor.
El segundo tipo de integrados (también llamados “intrínsecos”) permiten trucos y optimizaciones que difícilmente se pueden lograr con un static pieza de código que reside en una biblioteca. Pueden traducirse en dar pistas a la CPU (__builtin_prefetch
, __builtin_expect
), o mejorar el lenguaje C con una mejor introspección en tiempo de compilación (__builtin_constant_p
, __builtin_types_compatible_p
), o proporcionar una interfaz independiente de la plataforma más simple para algunas instrucciones específicas de la arquitectura (__builtin_ffs
, __builtin_popcount
).