Est-ce que printf peut être remplacé par put automatiquement dans un programme C?

#include  int puts(const char* str) { return printf("Hiya!\n"); } int main() { printf("Hello world.\n"); return 0; } 

Ce code génère “Hiya!” quand couru. Quelqu’un pourrait-il expliquer pourquoi?

La ligne de compilation est la suivante: gcc main.c

EDIT: c’est maintenant du pur C et toutes les choses superflues ont été supprimées de la ligne de compilation.

Oui, un compilateur peut remplacer un appel à printf par un appel équivalent à puts .

Étant donné que vous avez défini votre propre fonction avec le même nom qu’une fonction de bibliothèque standard, le comportement de votre programme n’est pas défini.

Référence: N1570 7.1.3:

Tous les identificateurs avec une liaison externe dans l’un des sous-paragraphes suivants [ceci inclut les puts ] sont toujours réservés à une utilisation en tant qu’identificateurs avec une liaison externe.
...
Si le programme déclare ou définit un identifiant dans un contexte dans lequel il est réservé (autre que celui autorisé par 7.1.4), ou définit un identifiant réservé en tant que nom de macro, le comportement est indéfini.

Si vous supprimez votre propre fonction de vente et examinez une liste d’assemblages, vous pouvez trouver un appel à qui puts le code généré à l’endroit où vous avez appelé printf dans le code source. (J’ai vu gcc effectuer cette optimisation particulière.)

Cela dépend du compilateur et du niveau d’optimisation. Les versions les plus récentes de GCC , sur certains systèmes courants, avec certaines optimisations, sont capables de réaliser une telle optimisation (remplacement d’une simple imprimante par des options de vente, AFAIU étant des normes légales telles que C99).

Vous devez activer les avertissements lors de la compilation (par exemple, essayez d’abord de comstackr avec gcc -Wall -g , puis de déboguer avec gdb , puis lorsque vous êtes sûr de votre code, comstackz-le avec gcc -Wall -O2 )

Au fait, redéfinir les options de vente est vraiment très moche, à moins que vous ne le fassiez express (c’est-à-dire que vous codez votre propre bibliothèque C, puis que vous devez respecter les normes). Vous obtenez un comportement indéfini (voir aussi cette réponse sur les conséquences possibles de l’UB). En fait, vous devriez éviter de redéfinir les noms mentionnés dans la norme, à moins que vous ne sachiez vraiment ce que vous faites et ce qui se passe dans le compilateur.

De plus, si vous avez compilé avec des liens statiques comme gcc -Wall -static -O main.c -o yourprog je parie que l’éditeur de liens se serait plaint (à propos d’une définition multiple de puts ).

Mais IMNSHO, votre code est tout simplement faux et vous le savez.

Vous pouvez aussi comstackr pour obtenir l’assembleur, par exemple avec gcc -fverbose-asm -O -S ; et vous pourriez même demander à gcc de répandre beaucoup de fichiers de “vidage”, avec gcc -fdump-tree-all -O qui pourrait vous aider à comprendre ce que fait gcc .

Encore une fois, cette optimisation particulière est valide et très utile : la routine printf de toute libc doit “interpréter” au moment de l’ exécution la chaîne de format d’impression (gestion de %s etc … spécialement); c’est en pratique assez lent. Un bon compilateur a raison d’éviter d’appeler printf (et de le remplacer par puts ) lorsque cela est possible.

BTW gcc n’est pas le seul compilateur à faire cette optimisation. clang aussi.

Aussi, si vous comstackz avec

 gcc -ffreestanding -O2 almo.c -o almo 

le programme almo montre Hello world.


Si vous voulez une autre optimisation fantaisiste et surprenante, essayez de comstackr

 // file bas.c #include  int f (int x, int y) { int r; int* p = malloc(2*sizeof(int)); p[0] = x; p[1] = y; r = p[0]+p[1]; free (p); return r; } 

avec gcc -O2 -fverbose-asm -S bas.c puis cherchez bas.s ; vous ne verrez aucun appel à malloc ou à free (en fait, aucune instruction de machine à call n’est émise) et encore une fois, gcc raison d’optimiser (et de clang )!

PS: Gnu / Linux / Debian / Sid / x86-64; gcc est la version 4.9.1, clang est la version 3.4.2

Essayez ltrace sur votre exécutable. Vous verrez que printf est remplacé par un appel du compilateur. Cela dépend de la façon dont vous avez appelé printf

Une lecture intéressante sur ceci est ici

Vraisemblablement, printf () de votre bibliothèque appelle put ().

Votre put () remplace la version de la bibliothèque.