2010-12-09 26 views
5

Je sais que C++ ne spécifie pas l'ordre dans lequel les paramètres sont transmis à une fonction. Mais si nous écrivons le code suivant:convention d'appel et ordre d'évaluation

void __cdecl func(int a, int b, int c) 
{ 
     printf("%d,%d,%d", a,b,c); 
} 
int main() 
{ 
    int i=10; 
    func(++i, i, ++i); 
} 

Peut-on dire de manière fiable la sortie serait 12,11,11 depuis le __cdecl veille à ce que l'ordre de passage argument est droite à gauche?

+0

Puisque je n'écrirais jamais de code comme celui-ci, je suis curieux de savoir ce qui a provoqué cette question. Quelle est la contrainte? –

+0

http://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points –

+0

En outre, vous n'avez pas lu le million et un article sur ne pas modifier une variable plus d'une fois dans une instruction. –

Répondre

12

selon la norme, il y a deux choses que vous devez comprendre et différencier:

  1. C++ ne précise pas l'ordre dans lequel les paramètres sont passé à une fonction (comme vous le dites vous-même, que est vrai!)
  2. C++ ne spécifie pas l'ordre dans lequel les arguments de la fonction sont évalué [expr.call].

Maintenant, s'il vous plaît noter, __cdecl assure que le premier, pas le second. Calling conventions décidez seulement comment les arguments de fonctions seront passés, left-to-right ou right-to-left; ils peuvent encore être évalués dans n'importe quel ordre!

Espérons que cela clarifie vos doutes concernant les conventions d'appel.

Toutefois, étant donné que ces conventions sont l'extension du compilateur Microsoft vers C++, votre code n'est pas portable. Dans ce cas, vous pouvez voir comment le compilateur MSVC++ évalue les arguments de la fonction et se détendre SI vous ne voulez pas exécuter le même code sur une autre plate-forme!


func(++i, i, ++i); 

Notez que ce code particulier invoque un comportement non défini, car i est incrémenté plus d'une fois sans quelconque intervenir un point quelconque de la séquence.

+0

La convention d'appel de bas niveau n'est pas la même chose que l'ordre d'évaluation des expressions. – seand

+0

Non seulement il n'est pas portable entre plates-formes, il n'est pas portable entre différents compilateurs sur la même plate-forme, ni même entre différentes versions du même compilateur sur la même plate-forme parce que ** comportement non défini **. –

+0

@Adam .. ouais, c'est vrai. – Nawaz

0

Vous modifiez la même variable plus d'une fois entre des points de séquence (l'évaluation de l'argument de fonction est un point de séquence), ce qui provoque un comportement indéfini quelle que soit la convention d'appel.

0

Non, vous ne pouvez pas le supposer.
Un compilateur d'optimisation mettra en évidence des fonctions courtes. Tout ce que __stdcall sera garanti est que la version __stdcall de la fonction sera générée, mais cela ne signifie pas que le compilateur ne peut pas également l'aligner dans le même temps.
Si vous voulez vraiment être sûr qu'il n'est pas en ligne, vous devez le déclarer dans une autre unité de compilation, même si des optimisations de liens peuvent être intégrées même dans ce cas.

De plus, l'ordre des paramètres sur la pile n'a rien à voir avec l'ordre dans lequel ils sont évalués.Par exemple, pour un appel de fonction fn(a, b, c) GCC généralement pas faire

push c 
push b 
push a 
call fn 

mais plutôt

sub esp, 0xC 
mov [esp+8], c 
mov [esp+4], b 
mov [esp], a 
call fn 

Notez que dans le second cas, il n'a pas de restrictions sur l'ordre.

0

Il est possible qu'une implémentation C particulière définisse ce que fera un compilateur dans certains cas, ce qui serait, selon la norme, un "comportement indéfini". Par exemple, définir une variable int sur ~ 0U constituerait un comportement indéfini, mais rien dans le standard C ne permettrait à un compilateur d'évaluer l'int comme -1 (ou -493, d'ailleurs). Il n'y a rien non plus qui interdirait à un fournisseur de compilateur particulier de déclarer que son compilateur particulier définira en fait la variable à -1. Puisque __cdecl n'est pas défini dans le standard C, et n'est applicable qu'à certains compilateurs, la question de savoir comment sa sémantique est définie dépend de ces fournisseurs; puisque le standard C le liste comme comportement non documenté, il ne sera documenté que dans la mesure où des fournisseurs particuliers le documentent.