2010-01-15 5 views
3

im juste curieux sur l'exemple suivantC - Quelle est la valeur de retour d'un point-virgule?

#include<stdio.h> 
int test(); 
int test(){ 
    // int a = 5; 
    // int b = a+1; 
    return ; 
} 
int main(){ 
    printf("%u\n",test()); 
    return 0; 
} 

i compilé avec gcc -Wall -o semicolon.c virgule 'pour créer un exécutable et gcc -Wall S semicolon.c' pour obtenir le code assembleur qui est:

.file "semicolon.c" 
    .text 
.globl test 
    .type test, @function 
test: 
    pushl %ebp 
    movl %esp, %ebp 
    subl $4, %esp 
    leave 
    ret 
    .size test, .-test 
    .section  .rodata 
.LC0: 
    .string "%u\n" 
    .text 
.globl main 
    .type main, @function 
main: 
    leal 4(%esp), %ecx 
    andl $-16, %esp 
    pushl -4(%ecx) 
    pushl %ebp 
    movl %esp, %ebp 
    pushl %ecx 
    subl $20, %esp 
    call test 
    movl %eax, 4(%esp) 
    movl $.LC0, (%esp) 
    call printf 
    movl $0, %eax 
    addl $20, %esp 
    popl %ecx 
    popl %ebp 
    leal -4(%ecx), %esp 
    ret 
    .size main, .-main 
    .ident "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3" 
    .section  .note.GNU-stack,"",@progbits 

depuis je ne suis pas un tel pro assembleur, je ne sais que des impressions printf ce qui est dans eax , mais je ne comprends pas bien ce que « movl% eax, 4 (% esp) » moyens Je suppose remplit eax avant d'appeler le test mais quelle est la valeur alors? ce qui signifie 4 (% esp) et que signifie la valeur de ESP?

si je décommenter les lignes test() imprime printf 6 - qui est écrit dans eax ^^

Répondre

9

Votre langage assembleur annotés:

test: 
    pushl %ebp  # Save the frame pointer 
    movl %esp, %ebp # Get the new frame pointer. 
    subl $4, %esp # Allocate some local space on the stack. 
    leave    # Restore the old frame pointer/stack 
    ret 

Notez que rien dans le test touche EAX.

.size test, .-test 
.section  .rodata 
.LC0: 
.string "%u\n" 
.text 
.globl main 
.type main, @function 
main: 
leal 4(%esp), %ecx  # Point past the return address. 
andl $-16, %esp   # Align the stack. 
pushl -4(%ecx)   # Push the return address. 
pushl %ebp    # Save the frame pointer 
movl %esp, %ebp   # Get the new frame pointer. 
pushl %ecx    # save the old top of stack. 
subl $20, %esp   # Allocate some local space (for printf parameters and ?). 
call test    # Call test. 

Notez qu'à ce stade, rien n'a modifié eax. Tout ce qui est entré dans le main est toujours là.

movl %eax, 4(%esp)  # Save eax as a printf argument. 
movl $.LC0, (%esp)  # Send the format string. 
call printf    # Duh. 
movl $0, %eax   # Return zero from main. 
addl $20, %esp   # Deallocate local space. 
popl %ecx    # Restore the old top of stack. 
popl %ebp    # And the old frame pointer. 
leal -4(%ecx), %esp  # Fix the stack pointer, 
ret 

Donc, ce qui est imprimé est ce qui est arrivé à la main. Comme d'autres l'ont souligné, il est indéfini: Cela dépend de ce que le code de démarrage (ou le système d'exploitation) a déjà fait pour eax.

+0

bonne explication. pour ajouter plus d'informations sur ce sujet, il semble que eax et son utilisation sur passer la valeur à travers la pile est similaire pour les types de données simples (int, double, char, void *, ...) mais comme il entre dans des structures plus de la gestion de la mémoire des compilateurs entre en jeu. Je ne sais pas encore ce qui se passe sur la pile dans le cas de structures pour comprendre le retour vide sur des fonctions non vides qui devraient renvoyer une structure, mais c'est une question/réponse plus complexe. de toute façon - thx –

+0

@John: à peu près la même chose arrive avec des structures qu'avec 'int's et' float's. Il s'appelle _stack trash_. Quoi qu'il arrive d'être dans la mémoire que l'appelant a réservé pour la valeur de retour est ce qui est retourné. –

7

Le point-virgule n'a pas de valeur de retour, ce que vous avez il y a un « retour à vide », comme celui utilisé pour revenir des fonctions vides - donc la fonction ne retourne rien.

Cela provoque effectivement un avertissement lors de la compilation:

warning: `return' with no value, in function returning non-void 

Et je ne vois rien placé dans eax avant d'appeler test. Environ 4 (% esp), cela signifie prendre la valeur du pointeur de la pile (esp) + 4. I.e. le mot avant-dernier sur la pile.

+0

semble que j'ai mélangé intel et syntaxe d'assemblage AT & T, donc votre droit, eax n'est pas écrit. donc 'movl% eax, 4 (% esp)' signifierait que eax est poussé à pile, non? –

+0

Non, cela signifie que la valeur de eax est stockée dans [esp + 4], c'est peut-être une variable locale sur la pile –

2

La valeur de retour d'une fonction int est transmise dans le registre EAX. La fonction de test ne définit pas le registre EAX car aucune valeur de retour n'est donnée. Le résultat est donc indéfini.

+0

donc le résultat n'est pas indéfini, mais la valeur trouvée dans eax, non? qui est par définition appelé 'non défini' –

+0

Oui, le résultat est la valeur dans EAX. Comme EAX n'est pas explicitement défini, sa valeur est déterminée par une opération précédente inconnue. C'est ce que nous appelons «indéfini». – Tomas

0

Un point-virgule n'a en effet aucune valeur.

Je pense que la bonne réponse est qu'un return <nothing> pour une fonction int est une erreur, ou a au moins un comportement indéfini. Voilà pourquoi la compilation cela avec -Wall donne

semi.c: In function ‘test’: 
semi.c:6: warning: ‘return’ with no value, in function returning non-void 

Quant à ce que le %4,esp tient ... c'est un endroit sur la pile où rien était (intentionnellement) stocké, il retournera probablement tout indésirable se trouve à cet endroit. Cela pourrait être la dernière expression évaluée aux variables dans la fonction (comme dans votre exemple) ou quelque chose de complètement différent. C'est ce que «indéfini» signifie. :)

Questions connexes