|
You have everything having to do with C++ there, but with .NET here - that is the difference.
Best regards,
Paul.
Jesus Christ is LOVE! Please tell somebody.
|
|
|
|
|
Hi,
i like to save received data files (.pmj) from a scanner serially numbered on my disc (001.pmj, 002.pmj, ...) I know i must work with a loop and a variable, but it is too tricky for me.
Untill now i do the following:
// Save the file...
if (r)
{
CString fileName = "e:\\data\\001.pmj";
SavePMJStream(fileName);
}
Thanks for help, Mark
|
|
|
|
|
Please this is MC++ forum, try the Visual C++ forum for MFC stuff.
Best regards,
Paul.
Jesus Christ is LOVE! Please tell somebody.
|
|
|
|
|
BTW in advance I apologize for this super lengthy post! Any help would be GREATLY apreciated. I am aware that my codeing is a bit messed up but thats ok.. for now.. the main thing is that I figure out how to put all this to use properly while understanding why it works.
Ok everybody I hope I am not stepping out of line in posting this question on this forum. I'm a new member of the code project and I am new to programing in general, have started programming in c++ but my knowledge is and will be fairly limmited for a while.. I am trying to put to use what I have learned in a simple program but have come across a problem. Mind you it could just be that my brain is completely fried from digesting 300 pages of the book I am studying to learn c++ in 3 days (OUCH!)
the program is as follows In brackets () I have put my questions hope this doesn't confuse anybody.. dont worry I havent use () in the program itself yet.
<br />
#include <stdio.h><br />
#include <iostream.h><br />
#include <string.h><br />
int main(int nNumberOfArgs, char* pzargs[])<br />
{
Int response;<br />
cout << "Enter a question or comment to which jeeney may respond:';<br />
cin >> response;<br />
//Calculate statement or question input to result a<br />
//coresponding statement or question to output
(The problem I have is here.. I need to create an "if" statement example
"if" input responce is "Hello Jeeney" "then" Jeeney would respond useing
another sentence or question such as Ex: "Hello, how are you today?"
I'm not entirely sure how to do this as I seem to be learning ONLY useing numbers. I somewhat understand HOW it should work but am not very sure of the codeing used.)
( int factor; this part is confuseing as well. I am working with character strings rather then integers so wouldn't this be more apropriately put as "char factor" ? and that doesn't seem to make any sence either.
( factor = )
return 0;<br />
}
|
|
|
|
|
Hello Caden,
To get a better response you will need to property phase your question.
Anyway, this forum is for MC++, try using the Visual C++ forum.
Best regards,
Paul.
Jesus Christ is LOVE! Please tell somebody.
|
|
|
|
|
OOPS! Go figure I'd mess up ... sorry!
|
|
|
|
|
Hi!
I am working on a function that returns an object initilized with some
specific values, like
<br />
__value struct MyStruct<br />
{<br />
public:<br />
MyStruct(int a, int b, int c)<br />
: a(in_a), b(in_b), c(in_c) {}<br />
<br />
static MyStruct One() { return MyStruct(1,1,1); }<br />
<br />
private:<br />
int a, b, c;<br />
};<br />
This is compiled to the following MSIL-code:
<br />
.method public static valuetype Cpp.MyStruct<br />
One() cil managed<br />
{<br />
.maxstack 4<br />
.locals (valuetype Cpp.MyStruct V_0)<br />
IL_0000: ldloca.s V_0<br />
IL_0002: initobj Cpp.MyStruct<br />
IL_0008: ldloca.s V_0<br />
IL_000a: ldc.i4.1<br />
IL_000b: ldc.i4.1<br />
IL_000c: ldc.i4.1<br />
IL_000d: call instance void Cpp.MyStruct::.ctor(int32,<br />
int32,<br />
int32)<br />
IL_0012: ldloca.s V_0<br />
IL_0014: ldobj Cpp.MyStruct<br />
IL_0019: ret<br />
}
I looked at IL_0002 and found a initobj. I tried to avoid initializing of
the members, so I defined an empty default c'tor:
MyStruct() {}
However, now my IL code expanded to:
<br />
.method public static valuetype Cpp.MyStruct<br />
One() cil managed<br />
{<br />
.maxstack 4<br />
.locals (valuetype Cpp.MyStruct V_0,<br />
valuetype Cpp.MyStruct V_1)<br />
IL_0000: ldloca.s V_1<br />
IL_0002: initobj Cpp.MyStruct<br />
IL_0008: ldloca.s V_1<br />
IL_000a: ldc.i4.1<br />
IL_000b: ldc.i4.1<br />
IL_000c: ldc.i4.1<br />
IL_000d: call instance void Cpp.MyStruct::.ctor(int32,<br />
int32,<br />
int32)<br />
IL_0012: ldloca.s V_0<br />
IL_0014: ldloca.s V_1<br />
IL_0016: cpobj Cpp.MyStruct<br />
IL_001b: ldloca.s V_0<br />
IL_001d: ldobj Cpp.MyStruct<br />
IL_0022: ret<br />
}
Which contains a cpobj and two local instances of MyStruct and therefore
seems to be even worse.
I wrote a similar struct in C# to compare compilation output:
<br />
public struct MyStruct<br />
{<br />
public MyStruct(int in_a, int in_b, int in_c)<br />
{<br />
a = in_a;<br />
b = in_b;<br />
c = in_c;<br />
}<br />
public static MyStruct One() { return new MyStruct(1, 1, 1); }<br />
int a, b, c;<br />
};<br />
This compiled to the following code:
<br />
.method public hidebysig static valuetype CSharp.MyStruct<br />
One() cil managed<br />
{<br />
.maxstack 8<br />
IL_0000: ldc.i4.1<br />
IL_0001: ldc.i4.1<br />
IL_0002: ldc.i4.1<br />
IL_0003: newobj instance void CSharp.MyStruct::.ctor(int32,<br />
int32,<br />
int32)<br />
IL_0008: ret<br />
}
Now I tested execution time and I am not really suprised: the the C++ struct
without default c'tor was about 30% slower than the C# version. The C++
Version with default c'tor even was 70% slower than the C# version.
Now I have two questions: first, is the C# version creating the object on
the heap or the stack?
And: how can I make the C++ version compile to the faster version?
Thanks in advance!
- Andre
|
|
|
|
|
Hello Andre,
VizOne wrote:
...is the C# version creating the object on
the heap or the stack?
As you suspected, the C# version is allocating on the heap, which is what the 'newobj' IL instruction normally does. So, the two pieces of code are not equivalent, and is partly why the instructions differ so.
The MC++ bit is dealing with a stack object, and even more importantly, is returning a copy of the object, not just a pointer (object reference in .Net lingo) to it. The 'ldobj' instruction verifies this, and I think a large part of the performance difference. Not only is the __value object initialised (initobj Cpp.MyStruct), but it's address is repeatedly pushed onto the stack (ldloca.s V_0) for various ops.
So the address of the static struct is loaded, it's initialised, the address is again loaded, constant params loaded, the ctor called, the object's address loaded yet again, then an entire copy made before returning. I can see why performance was bad.
However, I'm thinking the number of ops is not the most reliable way to gauge performance here. In particular, newobj does a lot for a single instruction, including runtime allocation on the GC heap, initialising, and then calling the ctor. Admittedly GC heap allocation is designed to be very fast, and nearly as fast as stack allocation, but the C# code does not make a copy. I suspect that's the biggest factor.
I'm curious if the code was optimised during compile, as that might make a significant difference. You have me digging deeper into this one, so I'll post back if I come up with anything more. I'll try making the MC++ and C# functions both return copies and pointers. Shame on you for stimulating my attrophied neurons! Interesting stuff.
Cheers
|
|
|
|
|
Jeff J wrote:
Shame on you for stimulating my attrophied neurons!
...and on you for coming out with something reasonable. I am still searching my references
Anyway, let us know the results of your research. MC++ is here to stay!!!
Best regards,
Paul.
Jesus Christ is LOVE! Please tell somebody.
|
|
|
|
|
Hello Paul,
Paul Selormey wrote:
MC++ is here to stay!!!
Yes it is! In fact, I'm counting on VS.Net 2003 making it a lot more popular. Looks like we'll be some of the few ahead of the game.
Cheers,
Jeff
|
|
|
|
|
Hello Andre (and Paul),
I played with the code you posted and some other stuff, but could not find a way to optimise the MC++ MSIL any further, but that may not be as much of a problem as we first thought. BTW, I can now see your MSIL was taken from optimised compiles.
Regarding your earlier question of whether the C# struct was being allocated on the stack or on the heap, I think I judged too quickly based on the MSIL. CIL documentation does not say much about newobj being applied to value types, however it "can" be used to allocate on the stack. It also says that it is rarely done this way. The blanks leave questions, but my guess is that newobj is itself optimised to return value types/structs as efficiently as possible, and in this unusual case, not on the heap. CLI instructions are not like low-level assembler op-codes, but more like convenient groups of instructions (actually, so are some op-codes).
Frustrated with MSIL, I moved to assembler, and found the following:
static MCppStruct GetStack() | public static CshStruct GetNew()
{ return MCppStruct(1,2,3); } | { return new CshStruct(1, 2, 3); }
-------------------------------------------------------------------------------------
00 push ebp | 00 push ebp
01 mov ebp,esp | 01 mov ebp,esp
03 sub esp,10h | 03 sub esp,10h
06 push edi | 06 push edi
07 push esi | 07 push esi
08 push ebx | 08 push ebx
09 <FONT color="green">mov ebx,ecx</FONT> |
0b <FONT color=blue>lea edi,[ebp-10h]</FONT> |
0e xor eax,eax | 09 xor eax,eax
10 <FONT color=blue>stos dword ptr [edi]</FONT> | 0b <FONT color=blue>mov dword ptr [ebp-10h],eax</FONT>
11 <FONT color=blue>stos dword ptr [edi]</FONT> | 0e <FONT color=blue>mov dword ptr [ebp-0Ch],eax</FONT>
12 <FONT color=blue>stos dword ptr [edi]</FONT> | 11 <FONT color=blue>mov dword ptr [ebp-8],eax</FONT>
| 14 <FONT color="green">mov ebx,ecx</FONT>
13 push 2 | 16 push 2
15 push 3 | 18 push 3
17 lea ecx,[ebp-10h] | 1a lea ecx,[ebp-10h]
1a mov edx,1 | 1d mov edx,1
1f call dword ptr ds:[00825230h] | 22 call dword ptr ds:[008151F0h]
25 mov edi,ebx | 28 mov edi,ebx
27 lea esi,[ebp-10h] | 2a lea esi,[ebp-10h]
2a movs dword ptr [edi],dword ptr [esi] | 2d movs dword ptr [edi],dword ptr [esi]
2b movs dword ptr [edi],dword ptr [esi] | 2e movs dword ptr [edi],dword ptr [esi]
2c movs dword ptr [edi],dword ptr [esi] | 2f movs dword ptr [edi],dword ptr [esi]
2d pop ebx | 30 pop ebx
2e pop esi | 31 pop esi
2f pop edi | 32 pop edi
30 mov esp,ebp | 33 mov esp,ebp
32 pop ebp | 35 pop ebp
33 ret | 36 ret
-------------------------------------------------------------------------------------
Most instructions are the same, except for those in blue. For the C# code, the JIT individually moves zero (in EAX) into the ints, whereas the MC++ stuff translates to using store-string (which requires loading the first address into EDI before the calls). They accomplish the same thing, and I don't recall that stos is slower than mov, so I'm stumped here. Best I can tell, performance should be about the same. The constructors were exactly the same. I don't see heap alloc here. So much for reading MSIL.
Is it possible that there is a difference in the code you used to test the performance? Maybe forgot to switch the MC++ to release mode as I originally did? Who knows, maybe the JIT settings used when debuggin' C# code, hides further optimisations done outside the IDE. I am assuming the disassembly view is accurate. Anyway, this has been a lesson for me that different byte codes can produce similar asm. Sorry for the short post
Regards,
Jeff
|
|
|
|
|
Hello Jeff,
Thanks for the great work you are doing. The assembler results is interesting.
I now wish Andre could post his test projects so that we could examine them too.
Anyway, keep it up. I now have to take my IL lessons serious
Best regards,
Paul.
Jesus Christ is LOVE! Please tell somebody.
|
|
|
|
|
Whoops, it seems I did not get an e-mail notification. Something's going on in here, I see.
I'm short on time right now, so I cannot post the test code (maybe it was a test way too naiv at all). I'll post it when I have a little more time.
Thanks already for the interesting research, Jeff!
- Andre
|
|
|
|
|
Do not know if you read this, this was a late response from MS:
In response to your questions:
1)
The C# version is creating the struct on the stack. Turns out newobj
instruction can be used to create value types on the stack. I verified
this from the CIL spec (http:
for CLI Partition III , which documents the CIL instruction set), and by
writing a small MC++ sample that successfully consumes a value type
returned from C# in this manner.
2)
Our team has entered a suggestion to see if we can generate more efficient
CIL for the sample you provided.
--
Andrew Brown, Visual C++ Team
This posting is provided AS IS with no warranties, and confers no rights.
Best regards,
Paul.
Jesus Christ is LOVE! Please tell somebody.
|
|
|
|
|
I hope this is my last MC++ newbie question for a while...
( btw, thanks to previous answers I've got my cross platform, C++ & MC++ agnostic
threading code running. Thanks! )
Is there any way to use templates for subclassing with managed classes ?
As in;
<br />
template<typename T><br />
struct foo<br />
{<br />
...<br />
};<br />
...<br />
__gc class bar<br />
: public foo<bar><br />
{<br />
...<br />
};<br />
..which doesn't compile. Adding a __gc to the foo-template doesn't help either. So, is there any way to do this, at all ?
cheers
-=jarl=-
|
|
|
|
|
-=jarl=- wrote:
I hope this is my last MC++ newbie question for a while...
I hope so too
The Word version of the MC++ reference is available for download and it contains the dos and donts.
To your question, MC++ cannot derive from standard C++ and vice versa. A pointer of either can, however, be contained.
MC++ has no support for template (a lie actually !!!)
Best regards,
Paul.
Jesus Christ is LOVE! Please tell somebody.
|
|
|
|
|
Thank you very much!
-=jarl=-
Laird Of Glenmore
|
|
|
|
|
Is this;
<br />
void bar( data_struct_t * structure )<br />
{<br />
stuff_handle_ = GCHandle::Alloc( structure ); <br />
data_struct_t * tmp = static_cast<data_struct_t*>(stuff_handle_.Target);<br />
tmp->data_ = 1;<br />
} <br />
effectively as safe as, or the same as, this ?
<br />
void bar( data_struct_t * structure )<br />
{<br />
data_struct_t __pin * pinned = structure;<br />
pinned->data_ = 1;<br />
}<br />
-=jarl=-
|
|
|
|
|
Not really. GCHandle is more versatile than a pointer pinned via __pin. A pinned pointer only remains pinned while it is in scope, and if not set to zero. For example, when a function that uses pinned pointers returns, any pinned objects are no longer pinned. I suppose one could just say the __pin is used on stack-allocated pointers.
GCHandle, on the other hand, allocates on the heap (which is why Free() must be called to release an Alloc()-allocated GCHandle). There are a few options for GCHandles, but a regular one stays allocated between function calls, like any object allocated via malloc() or unmanaged new.
Which is safer? Well, that depends on the lifetime requirements you have for the object in question. If the handle needs to remain pinned/valid when it goes out of scope, GCHandle would be the safe bet.
Cheers
|
|
|
|
|
|
I think this overlaps somewhat with the general problems people seem to have with mixing C++ and MC++ code when pointers enters the equation, but anyways, here it the problem:
I have an unmanaged struct like so:
<br />
__nogc struct foo<br />
{<br />
int data_;<br />
};<br />
and then I have a managed struct like so:
<br />
__gc struct bar<br />
{<br />
foo is_this_unmanaged_still;<br />
};<br />
And...this doesn't compile.
: error C3633: cannot define 'is_this_unmanaged_still' as a member of managed 'bar'
I don't have my MC++ books yet, so excuse me if this is a bit of a naff question, but I am in the middle of porting some C++ code to be cross-C++/MC++ compatible and these little diddlers are causing me some immediate headaches...;P
cheers
-=jarl=-
|
|
|
|
|
..sorry, the question wasn't really in there now, was it...?
my question is: why doesn't this work ?
...I have feeling I might have asked a completely stupid question here....
-=jarl=-
|
|
|
|
|
Hello there,
The following compiles...
#include "stdafx.h"
#using <mscorlib.dll>
#include <tchar.h>
using namespace System;
__nogc struct StdHello
{
int nSomething;
};
__value struct MCHello
{
StdHello member;
};
int _tmain(void)
{
Console::WriteLine(S"Hello World");
MCHello hello;
hello.member.nSomething = 2003227;
Console::WriteLine(__box(hello.member.nSomething));
return 0;
}
I hope you see the difference It pays to buy a book, if not read the MC++ reference it is quite informative.
Best regards,
Paul.
Jesus Christ is LOVE! Please tell somebody.
|
|
|
|
|
Ok, yes, I am waiting impatiently for my books, so in the meantime I'm
abusing the nice people at CodeProj...
Ok, you've answered my question; You can only contain a managed structure
in another managed structure.
cheers
-=jarl=-
|
|
|
|
|
-=jarl=- wrote:
Ok, you've answered my question; You can only contain a managed structure
in another managed structure.
No you did not get it, __nogc means StdHello is unmanaged. __value means MCHello is a managed structure, better called value.
Best regards,
Paul.
Jesus Christ is LOVE! Please tell somebody.
|
|
|
|
|