El orden de evaluación de las expresiones es comúnmente undefined. (C y C++ son la misma forma. Java siempre evalúa de izquierda a derecha). El compilador no ofrece control sobre él. Si necesita evaluar dos expresiones en un orden específico, escriba su código de manera diferente. Realmente no me preocuparía la cantidad de líneas de código. Las líneas son baratas; usa tantos como necesites Si usted se encuentra utilizando este patrón menudo, escribir una función que envuelve todo:
function GetFirstIfAvailable(DB: TDatabaseObject; const FieldName: string): Integer;
begin
if DB.First = 0 then
Result := DB.ReturnFieldI(FieldName)
else
Result := 0;
end;
su código original, probablemente no habría sido lo que quería, incluso si el orden de evaluación eran diferentes. Incluso si DB.First
no fuera igual a cero, la llamada a ReturnFieldI
todavía se evaluaría. Todos los parámetros reales se evalúan completamente antes de invocar la función que los usa.
Cambiar Math.pas no te ayudaría de todos modos. No controla en qué orden se evalúan sus parámetros reales. Para cuando los ve, ya se han evaluado hasta un valor booleano y un número entero; Ya no son expresiones ejecutables.
La convención de llamadas puede afectar el orden de evaluación, pero todavía no hay garantía. El orden en que los parámetros se insertan en la pila no necesita coincidir con el orden en el que se determinaron esos valores.De hecho, si encuentra que stdcall o cdecl le dan su orden de evaluación deseada (de izquierda a derecha), entonces están siendo evaluados en el orden inverso del que se les pasó.
La pascal convención de llamadas pasa argumentos de izquierda a derecha en la pila. Eso significa que el argumento de la izquierda es el que se encuentra en la parte inferior de la pila, y el argumento de la derecha está en la parte superior, justo debajo de la dirección de retorno. Si la función IfThen
usó esa convención de llamada, hay varias maneras de que el compilador podría lograr que la disposición de pila:
de la forma esperada, y es que cada argumento se evalúa y se empujó de inmediato:
push (DB.First = 0)
push DB.ReturnFieldI('awesomedata1')
call IfThen
evaluar los argumentos de derecha a izquierda y almacenar los resultados en los temporales hasta que son empujados:
tmp1 := DB.ReturnFieldI('awesomedata1')
tmp2 := (DB.First = 0)
push tmp2
push tmp1
call IfThen
Allo espacio de pila cado en primer lugar, y evaluar en el orden que sea conveniente:
sub esp, 8
mov [esp], DB.ReturnFieldI('awesomedata1')
mov [esp + 4], (DB.First = 0)
call IfThen
en cuenta que IfThen
recibe los valores de los argumentos en el mismo orden en los tres casos, pero las funciones no necesariamente llama en ese orden
La convención de llamada de registro predeterminada también pasa los argumentos de izquierda a derecha, pero los primeros tres argumentos que se ajustan se pasan en los registros. Los registros utilizados para pasar argumentos, sin embargo, son también los registros más comúnmente utilizados para evaluar expresiones intermedias. El resultado de DB.First = 0
debía pasarse en el registro EAX, pero el compilador también necesitaba ese registro para llamar al ReturnFieldI
y para llamar al First
. Probablemente fue un poco más conveniente evaluar la segunda función en primer lugar, de esta manera:
call DB.ReturnFieldI('awesomedata1')
mov [ebp - 4], eax // store result in temporary
call DB.First
test eax, eax
setz eax
mov edx, [ebp - 4]
call IfThen
Otra cosa a destacar es que su primer argumento es una expresión compuesta. Hay una llamada a función y una comparación. No hay nada que garantice que esas dos partes se realicen consecutivamente. El compilador puede obtener primero las llamadas de función llamando al First
y ReturnFieldI
, y luego comparar el valor de retorno First
con cero.
Incluso si existe la posibilidad, ¡no hagas esto! Si necesita que la llamada "Primero" sea la primera, entonces codifíquela de esa manera. En mi humilde opinión, en esta situación solo un 'si' explícito es razonable. –
Noto su humilde opinión, pero ¿no cree que la función If That está justo al revés para empezar? Si no fuera por ese parámetro opcional al final, siempre sería mucho más útil decir IfThen (TrueResult, FalseResult, BooleanFunction). Según su razonamiento, ¿podría decir "if (funciónA y función B) entonces comenzar fin"; siempre debe escribirse "if functiona if if functionb then begin end;" ? –
No necesariamente, porque la evaluación de acceso directo booleana es bien conocida, mientras que la orden de evaluación de los argumentos de función no lo es. Si, por lo general, es inútil porque ** siempre ** evalúa ** todos ** argumentos que en mi experiencia no se desean, lo que más deseo ** o ** es la expresión verdadera ** o ** la expresión falsa que se ejecutará . –