Archived

This topic is now archived and is closed to further replies.

crazemanx

MSVC++ Standard not inline functions?

Recommended Posts

crazemanx    128
Reading the documentation for MS Visual C++ it implies that inlining of functions is not supported in the Standard edition, only the Professional and Enterprise... is this correct? If so it sucks! Edited by - crazemanx on November 5, 2001 8:41:05 AM Edited by - crazemanx on November 5, 2001 8:41:43 AM

Share this post


Link to post
Share on other sites
yyy    122
Can''t you simply do it that way?
e.g.
#define getrandom( min, max ) (( rand() % (int)((( max ) + 1 ) - ( min ))) + ( min ))

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
yyy: That''s not inlining a function.. that''s defining a macro (which is very similar, but not exact). The only benifit of inline''s over macros (that i''ve found, and besides looks) is that you can overload an inlined function (aka, what if you want the same function for floats & ints and the ints version to use shifts, while the float version has to use muls/divs).

#define Div2i(num) (num>>1) //int version
#define Div2f(num) (num/2) //Float version

inline int Div2(int num)
{
return num>>1;
}

inline float Div2(float num)
{
return num/2;
}

As you can see, the inline is much simpler, because no matter what you''re working with, you can just call Div2, and not have to worry about ints or floats. Also, the format of inline functions is identical to regular functions (except for the "inline" part). Macros can be really good too though... because if you have 2 different structs (or classes) with the same members... you can use a single macro without overloading it. So, having the inlines can be/is important depending on how you look at it.

Billy

Share this post


Link to post
Share on other sites
Oluseyi    2116
quote:
Original post by yyy
Can''t you simply do it that way?
e.g.
#define getrandom( min, max ) (( rand() % (int)((( max ) + 1 ) - ( min ))) + ( min ))


Yes, but then you lose all the benefits of inline functions, such as typechecking (which can be the cause of major bugs). You also note the number of parentheses needed to ensure that a macro is properly interpreted? Inline functions are a little clearer in that regard.

quote:
Original post by crazemanx
Reading the documentation for MS Visual C++ it implies that inlining of functions is not supported in the Standard edition, only the Professional and Enterprise... is this correct? If so it sucks!

What did you expect? It''s a commercial product and there have to be incentives for you to buy the more expensive versions. If you want to write production code, you wouldn''t be using Standard version anyway (Pro''s not that expensive).

And if that still pisses you off, you can use one of the free compilers.

Share this post


Link to post
Share on other sites
NuffSaid    122
The standard Edition supports inlining. It just doesn''t support the fancy optimizations.

If you don''t believe me, try inlining a function and look at the generated asm.

The standard version even expands some of the std C functions inline (e.g. memcpy, strcpy, etc), which is kinda cool.

All in all, the standard version isn''t too bad.

Share this post


Link to post
Share on other sites
bishop_pass    109
One of the bigger advantages of inlining a function over using a macro is the ability to use curly braces and still return a value.

Try doing a while loop with curly braces in a macro and have it return a value.

However, you can do macros with multiple statements that return values. Here''s an example:

#define SetVec(V,x,y,z) (V[0] = x, V[1] = y, V[2] = z, V)

___________________________________

Share this post


Link to post
Share on other sites
crazemanx    128
quote:
Original post by NuffSaid
The standard Edition supports inlining. It just doesn''t support the fancy optimizations.

If you don''t believe me, try inlining a function and look at the generated asm.



Maybe I am barking up the wrong tree here, but here goes... My main concern here is in access functions obtaining private member variables from a class.

Here is a bit of example code:
  
class MyClass
{
private:
int A;
public:
int B;
int GetA() { return A; }
} C;

void main()
{
int MyInt;
MyInt = C.GetA();
MyInt = C.B;
}


That is the complete source file, created as an empty Win32 Console Application. Compiling using the default Win32 Release configuration, with the added flag /FAs to generate asm code gives this:


; *** code ommitted by me

; 13 : MyInt = C.GetA();

mov ecx, OFFSET FLAT:?C@@3VMyClass@@A
call ?GetA@MyClass@@QAEHXZ ; MyClass::GetA
mov DWORD PTR _MyInt$[ebp], eax

; 14 : MyInt = C.B;

mov eax, DWORD PTR ?C@@3VMyClass@@A+4
mov DWORD PTR _MyInt$[ebp], eax

; *** code ommitted by me

?GetA@MyClass@@QAEHXZ PROC NEAR ; MyClass::GetA, COMDAT
; 7 : int GetA() { return A; }

push ebp
mov ebp, esp
push ecx
mov DWORD PTR _this$[ebp], ecx
mov eax, DWORD PTR _this$[ebp]
mov eax, DWORD PTR [eax]
mov esp, ebp
pop ebp
ret 0
?GetA@MyClass@@QAEHXZ ENDP ; MyClass::GetA

; *** code ommitted


It is my understaiding that functions defined within the class declaration are automatically expanded inline. Is this the case here? I dont know much about asm code but it appears to be making a function call here, and it is clearly much more expensive than simply accessing a data member directly.

Can anyone enlighten me as to why all this is needed just to return a variable?
Thanks, Nick.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Are you compiling a release build? Inlining''s disabled by default for a debug build.

Share this post


Link to post
Share on other sites
Null and Void    1088
If you don''t want to pay for it, just download DevC++. Dev C++ uses a port of the GCC compiler, which has optimizations that are normally better than MSVC anyway. You''ll have to put up with a few quarks from Dev C++''s IDE and the MinGW32 port of the Win32 libraries, but it is still a very nice compiler.

[Resist Windows XP''s Invasive Production Activation Technology!]

Share this post


Link to post
Share on other sites
Shannon Barber    1681
quote:

Try doing a while loop with curly braces in a macro and have it return a value.



        
#define DoWhile(x, y, z)\

while(x)\

{\

y;\

}\

//fudge to "return" z

z

?

Magmai Kai Holmlor
- Not For Rent

Edited by - Magmai Kai Holmlor on November 5, 2001 10:16:53 PM

Edited by - Magmai Kai Holmlor on November 5, 2001 10:17:26 PM

Edited by - Magmai Kai Holmlor on November 5, 2001 10:17:41 PM

Share this post


Link to post
Share on other sites
bishop_pass    109
Magmai gets an ''A'' for effort, but unfortunately, fudge isn''t good enough.

You can''t do this:

  
R = myFunc (DoWhile (x, y, z));



___________________________________

Share this post


Link to post
Share on other sites
NuffSaid    122
Hmm, perhaps my class example might be too simplistic, but here''s the source and the assembly listing(both Release and Debug)

  
#include <iostream>

using namespace std;

class A
{
public:
A(const int a = 0) : m_nData(a)
{
//do nothing;

}

void SetData(const int a)
{
m_nData = a;
}

int GetData() const
{
return m_nData;
}

private:
int m_nData;
};


int main()
{

A a;
a.SetData(5);
cout<<"The value is " <<a.GetData() <<endl;

return 0;
}


Release Listing
  
29 : {

push ebp
mov ebp, esp
sub esp, 40 ; 00000028H

; 30 :
; 31 : A a;

mov DWORD PTR _a$[ebp], 0

; 32 : a.SetData(5);

mov DWORD PTR _a$[ebp], 5

; 33 : cout<<"The value is " <<a.GetData() <<endl;

mov eax, DWORD PTR _a$[ebp]
push eax
push OFFSET FLAT:??_C@_0O@NMLI@The?5value?5is?5?$AA@ ; `string''
push OFFSET FLAT:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::cout
call ??6std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@PBD@Z ; std::operator<<
add esp, 8
mov ecx, eax
call ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z ; std::basic_ostream<char,std::char_traits<char> >::operator<<
mov DWORD PTR $T9475[ebp], eax
push 10 ; 0000000aH
mov ecx, DWORD PTR $T9475[ebp]
call ?put@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV12@D@Z ; std::basic_ostream<char,std::char_traits<char> >::put
mov DWORD PTR __St$9471[ebp], 0
mov ecx, DWORD PTR $T9475[ebp]
mov edx, DWORD PTR [ecx]
mov eax, DWORD PTR [edx+4]
mov ecx, DWORD PTR $T9475[ebp]
mov edx, DWORD PTR [ecx+eax+4]
mov DWORD PTR $T9370[ebp], edx
mov eax, DWORD PTR $T9370[ebp]
and eax, 6
neg eax
sbb eax, eax
neg eax
and eax, 255 ; 000000ffH
test eax, eax
jne SHORT $L9472
mov ecx, DWORD PTR $T9475[ebp]
mov edx, DWORD PTR [ecx]
mov eax, DWORD PTR [edx+4]
mov ecx, DWORD PTR $T9475[ebp]
mov edx, DWORD PTR [ecx+eax+40]
mov DWORD PTR $T9378[ebp], edx
mov eax, DWORD PTR $T9378[ebp]
mov edx, DWORD PTR [eax]
mov ecx, DWORD PTR $T9378[ebp]
call DWORD PTR [edx+44]
mov DWORD PTR $T9382[ebp], eax
cmp DWORD PTR $T9382[ebp], -1
jne SHORT $L9472
mov eax, DWORD PTR __St$9471[ebp]
or al, 4
mov DWORD PTR __St$9471[ebp], eax
$L9472:
mov ecx, DWORD PTR $T9475[ebp]
mov edx, DWORD PTR [ecx]
mov eax, DWORD PTR $T9475[ebp]
add eax, DWORD PTR [edx+4]
mov DWORD PTR $T9405[ebp], eax
cmp DWORD PTR __St$9471[ebp], 0
je SHORT $L9474
mov ecx, DWORD PTR $T9405[ebp]
mov edx, DWORD PTR [ecx+4]
mov DWORD PTR $T9387[ebp], edx
mov eax, DWORD PTR $T9387[ebp]
or eax, DWORD PTR __St$9471[ebp]
mov DWORD PTR $T9395[ebp], eax
mov ecx, DWORD PTR $T9405[ebp]
cmp DWORD PTR [ecx+40], 0
jne SHORT $L9465
mov edx, DWORD PTR $T9395[ebp]
or edx, 4
mov DWORD PTR -40+[ebp], edx
jmp SHORT $L9466
$L9465:
mov eax, DWORD PTR $T9395[ebp]
mov DWORD PTR -40+[ebp], eax
$L9466:
push 0
mov ecx, DWORD PTR -40+[ebp]
push ecx
mov ecx, DWORD PTR $T9405[ebp]
call ?clear@ios_base@std@@QAEXH_N@Z ; std::ios_base::clear
$L9474:

; 34 :
; 35 : return 0;

xor eax, eax

; 36 : }




Debug Listing
  


; 29 : {

push ebp
mov ebp, esp
sub esp, 68 ; 00000044H
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-68]
mov ecx, 17 ; 00000011H
mov eax, -858993460 ; ccccccccH
rep stosd

; 30 :
; 31 : A a;

push 0
lea ecx, DWORD PTR _a$[ebp]
call ??0A@@QAE@H@Z ; A::A

; 32 : a.SetData(5);

push 5
lea ecx, DWORD PTR _a$[ebp]
call ?SetData@A@@QAEXH@Z ; A::SetData

; 33 : cout<<"The value is " <<a.GetData() <<endl;

push OFFSET FLAT:?endl@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@1@AAV21@@Z ; std::endl
lea ecx, DWORD PTR _a$[ebp]
call ?GetData@A@@QBEHXZ ; A::GetData
push eax
push OFFSET FLAT:??_C@_0O@NMLI@The?5value?5is?5?$AA@ ; `string''
push OFFSET FLAT:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::cout
call ??6std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@PBD@Z ; std::operator<<
add esp, 8
mov ecx, eax
call ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z ; std::basic_ostream<char,std::char_traits<char> >::operator<<
mov ecx, eax
call ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV01@AAV01@@Z@Z ; std::basic_ostream<char,std::char_traits<char> >::operator<<

; 34 :
; 35 : return 0;

xor eax, eax

; 36 : }

Share this post


Link to post
Share on other sites
crazemanx    128
NuffSaid: Compiling your code with my VC++ standard i get the exact same listing for the Debug version, but for my Release settings i get:


; 24 : {

push ebp
mov ebp, esp
push ecx

; 25 : A a;

push 0
lea ecx, DWORD PTR _a$[ebp]
call ??0A@@QAE@H@Z ; A::A

; 26 : a.SetData(5);

push 5
lea ecx, DWORD PTR _a$[ebp]
call ?SetData@A@@QAEXH@Z ; A::SetData

; 27 : cout<<"The value is " <
push OFFSET FLAT:?endl@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@1@AAV21@@Z ; std::endl
lea ecx, DWORD PTR _a$[ebp]
call ?GetData@A@@QBEHXZ ; A::GetData
push eax
push OFFSET FLAT:$SG7462
push OFFSET FLAT:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::cout
call ??6std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@PBD@Z ; std::operator<<
add esp, 8
mov ecx, eax
call ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z ; std::basic_ostream >::operator<<
mov ecx, eax
call ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV01@AAV01@@Z@Z ; std::basic_ostream >::operator<<

; 28 : return 0;

xor eax, eax

; 29 : }


Again no inlining going on here. I checked the copliler options regarding inlining and found no /Ob flags set,
i set the /Ob2 flag (meaning 'any suitable inling') and got the compiler warning:

"ignoring unknown option '/Ob2'"

And my code was still not inlined. The same happens with /Ob1.


From the MSDN Library:
quote:

/Ob (In-line Function Expansion)
Home | Overview | How Do I | Compiler Options

***
Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.
***

The In-line Function Expansion (/Obn) options control inline expansion of functions, where n is one of the following:

Command Line Project Settings Description
/Ob0 Disable Disables inline expansion (default)
/Ob1 Only __inline Expands only functions marked as inline or __inline or, in a C++ member function, defined within a class declaration (default with /O1, /O2, and /Ox)
/Ob2 Any Suitable Expands functions marked as inline or __inline and any other function that the compiler chooses (expansion occurs at compiler discretion—often referred to as “auto-inlining”)




So if its true what everyone says that the standard edition supports inlining, how do I get it to do it?
My edition is just a standalone VC++6.0 Standard box bought from the local shop.
Nick.




Edited by - crazemanx on November 7, 2001 7:21:52 AM

Share this post


Link to post
Share on other sites
NuffSaid    122
That looks almost identical to the Debug version. That''s very very strange.

I''m pretty sure you didn''t set it to Release Build. This might sound really stupid, but here''s how you set the release build.

Build->Set Active Configuration->Release.

It is a mistake I made last time while I was learning to use MSVC. I just went to project settings and thought that was it.

Share this post


Link to post
Share on other sites
crazemanx    128
It definitely a release build, here is the output window message:

--------------------Configuration: inline3 - Win32 Release--------------------

inline3.exe - 0 error(s), 0 warning(s)


Here are the compiler flags in full, from the project options box:

/nologo /ML /W3 /GX /O2 /D "WIN32" /D
"NDEBUG" /D "_CONSOLE" /D "_MBCS" /FAs
/Fa"Release/" /Fp"Release/inline3.pch"
/YX /Fo"Release/" /Fd"Release/" /FD /c

And before you ask, i did load the inline3.asm file from the \Release folder not the \Debug folder!

Are you definitely using the standard version? Did you get is as part of a whole Visual Studio package or standalone, maybe there is a difference there?
Nick

Share this post


Link to post
Share on other sites
NuffSaid    122
Definitely the Standard Version. That''s what it says on the CD, the Box, and the startup screen. I got it for about £60 (got ripped off). Just Visual C++, no VB, VFP, etc.

Perhaps its due to Service Pack 5 that I installed? Or it could be that it just likes me

Share this post


Link to post
Share on other sites
crazemanx    128
Dude!
I installed service pack 4 from my cd in the box and hey presto its inlining all the way!
Silly me. Thanks for your help in getting to the bottom of this problem!
Cheers
Nick

Share this post


Link to post
Share on other sites
NuffSaid    122
We should all thank MS for writing buggy software I think it is probably a bug in the SP upgrade that patches you compiler (cl.exe) with the one that comes with the Pro/Enterprise version. Which explains why it is inlining your code.

At least, that''s what I think, now that someone has confirmed that the service pack enables inlining. I''m gonna try adding the optimization commands when I get home.

Share this post


Link to post
Share on other sites