Why does this code work?

Started by
10 comments, last by ph33r 21 years, 1 month ago
There must be something going on with the compiler that I don''t know about. If you notice after the while loop I do not return a value, but for some reason it does return the correct value. I''m very confused.
  
#include <iostream>

using namespace std;

int GCD(int, int);

int main()
{
	int x, y;

	cout << "Enter two integers\n1: ";
	cin >> x;
	cout << "2: ";
	cin >> y;
	cout << "The greatest common denominator of these numbers is " << GCD(x, y) << endl;
	system("PAUSE");

	return 0;
}

int GCD(int x, int y)
{
	int temp;

	if(x > y)
		if(x % y == 0)
			return y;
	if(y > x)
		if(y % x == 0)
			return x;



	while (x > 0)
	{
		temp = x;
		x = y % x;
		y = temp;
	}

}  
Advertisement
Here is the dissassembly of your GCD function.


    --- C:\Documents and Settings\Sysop\Desktop\Test\test.cpp  -----------------------------------------------------------------15:16:   int GCD(int x, int y)17:   {00401920   push        ebp00401921   mov         ebp,esp00401923   sub         esp,44h00401926   push        ebx00401927   push        esi00401928   push        edi00401929   lea         edi,[ebp-44h]0040192C   mov         ecx,11h00401931   mov         eax,0CCCCCCCCh00401936   rep stos    dword ptr [edi]18:       int temp;19:       if(x > y)00401938   mov         eax,dword ptr [ebp+8]0040193B   cmp         eax,dword ptr [ebp+0Ch]0040193E   jle         GCD+30h (00401950)20:           if(x % y == 0)00401940   mov         eax,dword ptr [ebp+8]00401943   cdq00401944   idiv        eax,dword ptr [ebp+0Ch]00401947   test        edx,edx00401949   jne         GCD+30h (00401950)21:               return y;0040194B   mov         eax,dword ptr [ebp+0Ch]0040194E   jmp         GCD+66h (00401986)22:       if(y > x)00401950   mov         ecx,dword ptr [ebp+0Ch]00401953   cmp         ecx,dword ptr [ebp+8]00401956   jle         GCD+48h (00401968)23:           if(y % x == 0)00401958   mov         eax,dword ptr [ebp+0Ch]0040195B   cdq0040195C   idiv        eax,dword ptr [ebp+8]0040195F   test        edx,edx00401961   jne         GCD+48h (00401968)24:               return x;00401963   mov         eax,dword ptr [ebp+8]00401966   jmp         GCD+66h (00401986)25:26:       while (x > 0)00401968   cmp         dword ptr [ebp+8],00040196C   jle         GCD+66h (00401986)27:       {28:           temp = x;0040196E   mov         edx,dword ptr [ebp+8]00401971   mov         dword ptr [ebp-4],edx29:           x = y % x;00401974   mov         eax,dword ptr [ebp+0Ch]00401977   cdq00401978   idiv        eax,dword ptr [ebp+8]0040197B   mov         dword ptr [ebp+8],edx30:           y = temp;0040197E   mov         eax,dword ptr [ebp-4]00401981   mov         dword ptr [ebp+0Ch],eax31:       }00401984   jmp         GCD+48h (00401968)32:   }00401986   pop         edi00401987   pop         esi00401988   pop         ebx00401989   mov         esp,ebp0040198B   pop         ebp0040198C   ret    


If you notice, the compiler has assumed what should be returned, and it added that code for you.

I was wrong, read CWizards second post, and my post after that.

[edited by - yummy_potatoes on March 2, 2003 12:39:55 PM]

[edited by - yummy_potatoes on March 2, 2003 12:49:48 PM]
"I once thought I was wrong, but then I was mistaken." - A4
I think this does not work, it just happen by chance to behave as expected. You should have a warning about that not all control paths return a value. This will cause the function to return an undefined value in those cases. In this case, probably whatever is in eax, which might be just what you intend to return. This is pure speculation, though.

quote:Original post by yummy_potatoes
If you notice, the compiler has assumed what should be returned, and it added that code for you.
No, i do not notice that. The value that the function returns is the value that is in eax when it comes back from the call. I can''t see that the compiler has inserted anything like that.

Ahh, yes. It would indeed return whatever is in EAX, because that is the standard register for that kind of thing. I just now remembered that in MASM32, you get your return value from EAX after invoking a function.
"I once thought I was wrong, but then I was mistaken." - A4
What exactly is the EAX register for, and why do they use it to store temporary values and the return value.

I tried looking it up and I found that AX was the incremental register though I didn''t see an EAX for. Also I stepped through the dissasembly and I saw that every temp variable the compiler used was stored in EAX.

Any incite would be helpfull.
quote:Original post by ph33r
What exactly is the EAX register for, and why do they use it to store temporary values and the return value.


EAX is merely an extended register. AX is a 16-bit register used mostly with old DOS programs. EAX has an extra 16 bits tacked onto it, making it 32 bit. Basically, they both serve the same purpose (accumulators).

Edit: as to why it's used to store temporary values, well, working with registers is a LOT faster than with RAM. Technically, you could stock temporary values in RAM, but it would be rather unefficient. For instance...
SomeValue = (SomeValue / 2) + (OtherValue - SomeValue) * 1.5
...would have to be transformed into...
TempA = OtherValue
TempA -= SomeValue
TempA *= 1.5
TempB = SomeValue
TempB /= 2
SomeValue = TempB
SomeValue += TempA
...which adds a good deal of overhead. You have to load and write variables a lot, and since assembly can only work with registers directly in the first place, you'd only end up wasting your time and chewing up unecessary cycles.

[edited by - RuneLancer on March 3, 2003 9:48:27 AM]
+----------------------------------+|               EAX                |+----------------------------------++-----------------+----------------+|     Unnamed     |        AX      |+-----------------+--------+-------++-----------------+--------+-------+|     Unnamed     |   AH   |   AL  |+-----------------+--------+-------+ 

EAX refers to the full 32bits,
AX refers to the lower 16bits that EAX names,
AH refers to the upper 8bits that AX names,
AL refers to the lower 8bits that AX names.

I am unsure why it is used so much for strogin temporary values, but I think I read somewhere that it was faster (closer to the circuitry that actually performs the additions.)

And unlike RuneLancer said, it is my understanding (not sure, I am still learning ASM myself), that you can directly refer to RAM, but it is slow as hell compared to just using the CPU's built in memory.

[edited by - yummy_potatoes on March 3, 2003 2:03:12 PM]
"I once thought I was wrong, but then I was mistaken." - A4
study some CPU architechture and you will understand
The reasons (E)AX is used to store temporary variables are as follows:

1. Certain instructions (f.i. mov, add, sub...) cannot accept arguments in the form mem32,mem32... that is the following is invalid:
mov tmp1,tmp2
Instead, you have to do the following:
mov ax,tmp1
mov tmp2,ax
Obviously, to just store tmp1->ax in the first place is more efficient than moving it into ax every time.

2. Certain other instructions (f.i. mul and imul) automatically use the (e)ax register to preform multiplication, that is the mul works as follows:
mov ax,tmp1
mul tmp2
mov result,ax
and not:
mul tmp1,ax ; or any similiar combination of operands

3. Add to that the fact that accessing registers is significantly faster than accessing memory (registers are on the processor whereas memory is usually located over a bus).

-- Exitus Acta Probat --

This topic is closed to new replies.

Advertisement