Hello!
I have a problem and I would like to ask if this is possible to do.
I have asm library, and I would like to pass two arrays and two 2d arrays. First is matrix given, second is result matrix third is matrix with answers and last is matrix with results after calculations. Last parameter is length. For example if last param is 5 you have matrixes 5x5, 5, 5x5, 5.
This is code in c++:
typedef int(_stdcall *DLLFunc)(double**, double*, double**, double*, int);
than in main function:
hDll = LoadLibrary("FibAsmLib");
if (hDll != NULL){
//proc = GetProcAddress(hDll, "MyProc");
myAsmProc = (DLLFunc)GetProcAddress(hDll, "MyProc");
if (myAsmProc != NULL){
result = myAsmProc(arrayA, arrayB, arrayAlfa, arrayBeta, rowA);
}
}
How am I supposed to operate on this pointers in asm? How to get any value from that array?
My code in asm:
.486
.model flat, stdcall
.data
.code
PUBLIC MyProc
MyProc proc w: DWORD, x:DWORD, y:DWORD, z:DWORD, e:DWORD
mov eax, 5
ret
MyProc endp
end
Library is connected correctly.
What you want is certainly possible. You pass pointers to matrices - just use them. Suppose you want to return the sum w(n)+y(n) in x:
MyProc proc uses esi edi w: DWORD, x:DWORD, y:DWORD, z:DWORD, e:DWORD
xor ecx, ecx
; int 3
mov esi, w
mov edx, y
mov edi, x
.Repeat
mov eax, [esi+DWORD*ecx] ; get w value from element ecx
add eax, [edx+DWORD*ecx] ; add y value from element ecx
mov [edi+DWORD*ecx], eax ; store in destination element ecx
inc ecx
.Until ecx>e ; could be > or >=, check yourself
ret
Besides, you should certainly uncomment the ; int 3, set Olly (http://www.ollydbg.de/version2.html) as your just in time debugger, and follow step by step using the F7 key.
Welcome to the forum :icon14:
Hello, thanks for answer. My job is to do the same thing in c++ and in assembler and compare results.
This is my code in c++ which is in an external library.
CPPLIBRARY_API int fnCPPLibrary(double** A, double* B, double** alfa, double* beta, int n){
for (int i = 0; i < n; i++){
if (A[i][i] == 0) {
std::cout << "You cant create alfa and beta matrix" << std::endl << "Devision by 0!" << std::endl;
return 1;
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i == j) alfa[i][j] = 0;
else
alfa[i][j] = -(A[i][j] / A[i][i]);
}
beta[i] = B[i] / A[i][i];
}
return 0;
}
Is this very complicated? I have never wrote code in assembler. Code in c++ was easy as pie. Can you give me some help?
the forum search tool might help
i seem to recall a few threads related to C-called asm functions
probably one easy way is to use a static library
so - that might be a good search term
If I could find a solution myself i would try to solve it and definetly I wouldn't waste your time. I need some good advices :)
Hi,
Quote from: pawkondr on January 15, 2015, 02:13:58 AM
My job is to do the same thing in c++ and in assembler and compare results.
For the following line of code;
for (int i = 0; i < n; i++) {
The assembly code could look like this:
NTest EQU 5 ; Assign a value for "n". Or MOV the value
; into a register to test against.
MOV [IndexI],0 ; int i = 0;"
ForI: ; Top of for loop. "for ("
CMP [IndexI],NTest ; "i < n;"
JGE ForEnd
; Do stuff "{ ... }"
INC [IndexI] ; "i++"
JMP ForI
ForEnd:
Does that help or hurt?
Regards,
Steve N.
Hi pawkondr
My version of JWasm has built in .FOR - .ENDFOR loop
To type the separator '¦' pres ALT then type 221 and release ALT
I promise you it will work faster than C++
you can write something like this:
.for (ebx=0¦ebx<n¦ebx++)
.for (edi=0¦edi<n¦edi++)
;some code
.endfor
.endfor
Ok, thanks for answers. How to get value from correct field in array? like a[index i][index j] in c++?
Quote from: pawkondr on January 15, 2015, 06:14:16 AM
If I could find a solution myself i would try to solve it and definetly I wouldn't waste your time. I need some good advices :)
i would help more if i could
i just don't write much code in anything but assembler
i can make a static library, however :P
Here is part of the solution - more attached, with sources in *.asc aka RTF format.
Quote from: pawkondr on January 15, 2015, 08:12:02 AM
How to get value from correct field in array? like a[index i][index j] in c++?
Check in particular the
lea instruction in the source.
include \masm32\include\masm32rt.inc
.code
fnCPPLibrary proc uses esi edi ebx pA, B:DOUBLE, pAlfa, beta:DOUBLE, n ; double** A, double* B, double** alfa, double* beta, int n) $export (keyword for building the dll with RichMasm)
mov esi, pA
A equ <DOUBLE ptr [esi]>
mov edi, pAlfa
alfa equ <DOUBLE ptr [edi]>
i equ <eax>
j equ <ebx>
mov i, 0
.While i<n
mov j, 0
.While j<n
push eax
.if i==j
imul eax, i, DOUBLE ; alfa[j]=0
imul n
lea eax, [eax+j*DOUBLE]
; deb 4, "Loop", eax ; debug macro needs MasmBasic (http://masm32.com/board/index.php?topic=94.0)
fldz ; alfa[j]=0
.else
imul eax, i, DOUBLE
imul n ; i*n
mov edx, [esp]
lea eax, [eax+edx*DOUBLE]
fld A[eax] ; A
imul eax, dword ptr [esp], DOUBLE
imul n
lea eax, [eax+j*DOUBLE]
; deb 4, "Loop", eax
fld A[eax] ; A[j]
fchs ; change sign
fdiv ; divide: alfa[j] = -(A[j] / A)
.endif
fstp alfa[eax]
pop eax
inc j
.Endw
inc i
.Endw
ret
fnCPPLibrary endp
LibMain proc instance:DWORD, reason:DWORD, unused:DWORD
m2m eax, TRUE
ret
LibMain endp
end LibMainOutput using a 5x5 matrix:mxA DOUBLE 100.0, 100.1, 100.2, 100.3, 100.4
DOUBLE 101.0, 101.1, 101.2, 101.3, 101.4
DOUBLE 102.0, 102.1, 102.2, 102.3, 102.4
DOUBLE 103.0, 103.1, 103.2, 103.3, 103.4
DOUBLE 104.0, 104.1, 104.2, 104.3, 104.4
mxB DOUBLE rows*columns dup(?)
; * c0 c1 c2 c3 c4
; r0 0.000 -0.999 -0.998 -0.997 -0.996
; r1 -1.001 0.000 -0.999 -0.998 -0.997
; r2 -1.002 -1.001 0.000 -0.999 -0.998
; r3 -1.003 -1.002 -1.001 0.000 -0.999
; r4 -1.004 -1.003 -1.002 -1.001 0.000
Thanks for your answer, I am impressed :)
But i need to do this as a library in visual studio. I must have code inside that library and then i need to call this function from my cpp code which i gave in first post. How to do that with that code from post above?
Thanks for all your help. I am so grateful.
you haven't said whether you want a static library or dynamic one
but, here is an example of a static lib, written in ASM
all you need is a simple C header file to include it into a C project
http://masm32.com/board/index.php?topic=2743.msg29059#msg29059 (http://masm32.com/board/index.php?topic=2743.msg29059#msg29059)
Here is my library, project from visual studio. It must be called from this code in c++:
hDll = LoadLibrary("FibAsmLib");
if (hDll != NULL){
myAsmProc = (DLLFunc)GetProcAddress(hDll, "MyProc");
if (myAsmProc != NULL){
result = myAsmProc(arrayA, arrayB, arrayAlfa, arrayBeta, rowA);
}
}
You are still showing code that loads a DLL, so my previous code would perfectly fit.
However, if you prefer a static library, it's attached. The source file is in RTF format.
You call MyProc exactly as you would call your static C++ library. Just change the library name.
Hello again, I tried to change called library name but it throws me error like this:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
And if I try to paste code that you wrote to me to my dll, that I created visual throws me some errors too:
Error 1 error A1000: cannot open file : \masm32\include\masm32rt.inc
Error 2 error MSB3721: The command "ml.exe /c /nologo /Zi /Fo"Debug\fibAsm.obj" /W3 /errorReport:prompt /TafibAsm.asm" exited with code 1. C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\BuildCustomizations\masm.targets 50 5 FibAsmLib
This language is killing me :(
Thanks for answers
Quote from: jj2007 on January 16, 2015, 02:11:37 AMYou call MyProc exactly as you would call your static C++ library.
Post the VS "project" where you CALL your static C++ library, complete with the arrays and the output that your proggie produces. There must be something like
MyProc(bunch, of, paras);That is what we need to see. And btw assembler is a lot easier and simpler than C++.
i would imagine that C procedures default to C calling convention
we often use StdCall in ASM - and most windows API's also use this convention
so - see how they are defined and how they are prototyped - you probably have a mismatch somewhere
Hello again, I have uploaded my whole VS2013 solution. It was much larger than 0,5 MB so, I put it on Google Drive. Here is the link:
https://drive.google.com/file/d/0B0kbQ3Gi5BRTdDgtQXJrUGw3b0E/view?usp=sharing (https://drive.google.com/file/d/0B0kbQ3Gi5BRTdDgtQXJrUGw3b0E/view?usp=sharing)
163,154,560 bytes for a hello world proggie? I love C++ :greensml:
Besides, my version of VS doesn't like it, see below, and the only interesting part is this:
hDll = LoadLibrary("FibAsmLib");
if (hDll != NULL){
myAsmProc = (DLLFunc)GetProcAddress(hDll, "MyProc");
if (myAsmProc != NULL){
result = myAsmProc(arrayA, arrayB, arrayAlfa, arrayBeta, rowA);
}
That is code for loading a DLL, as mentioned twice in this thread, and it is only slightly different from linking to a static lib. Once you are able to link to a static C++ library, and using myAsmProc(arrayA, arrayB, arrayAlfa, arrayBeta, rowA);, show us that part only.
Ok, I will do that.
BTW. Try to open .sln file in notepad and change this lines:
Microsoft Visual Studio Solution File, Format Version 12.00
Visual Studio 2013
To:
Microsoft Visual Studio Solution File, Format Version 10.00
Visual Studio 2010
Quote from: pawkondr on January 17, 2015, 10:48:59 AM
Ok, I will do that.
BTW. Try to open .sln file in notepad and change this lines:
Microsoft Visual Studio Solution File, Format Version 12.00
Visual Studio 2013
To:
Microsoft Visual Studio Solution File, Format Version 10.00
Visual Studio 2010
This is a hilarious hack, but the converter swallows it :t
However, VS then complains that the toolset is not valid. OK, Google is our friend, and many many people are fighting with Microsoft, so that is also solved.
The good news: your project builds without errors, and it even runs!!!
Until it hits this simple line:
hDll =
LoadLibrary("FibAsmLib");
And then, Windows 7-64 complains that MSVCR120.dll is not present on the computer.
Seriously, what else do you expect from a hello world proggie that needs 163,154,560 bytes of disk space?
Redmond!! REEEEEDDDDDMMOOOOOOOND!!!!
QuoteThere was once a young man who, in his youth, professed his desire to become a great writer. When asked to define "great" he said, "I want to write stuff that the whole world will read, stuff that people will react to on a truly emotional level. Stuff that will make them scream, cry, and howl in pain and anger!"
He now works for Microsoft, writing error messages.
QuoteA helicopter was flying around above Seattle when an electrical malfunction disabled all of the aircraft's electronic navigation and communications equipment. Due to the clouds and haze, the pilot could not determine the helicopter's position and course to fly to the airport. The pilot saw a tall building, flew toward it, circled, drew a handwritten sign, and held it in the helicopter's window. The pilot's sign said "WHERE AM I?" in large letters. People in the tall building quickly responded to the aircraft, drew a large sign, and held it in a building window. Their sign read "YOU ARE IN A HELICOPTER." The pilot smiled, waved, looked at his map, determined the course to steer to SEATAC airport, and landed safely. After they were on the ground, the co-pilot asked the pilot how the "YOU ARE IN A HELICOPTER" sign helped determine their position. The pilot responded "I knew that had to be the Microsoft building because they gave me a technically correct, but completely useless answer."
Back to work: I attach a version of your Main.cpp that builds and runs because it uses a static lib. Main points:
#define asmLibDll 0
#if asmLibDll==0
#pragma comment(lib, "testJJ.lib") // the static library
extern "C" int __stdcall myAsmProc(double** A, double* B, double** alfa, double* beta, int n);
#endif
#if asmLibDll
DLLFunc myAsmProc;
#endif
//ASM library
#if asmLibDll==0
//_asm int 3;
cout << "\n#elements=" << rowA;
result = myAsmProc(arrayA, arrayB, arrayAlfa, arrayBeta, rowA);
//_asm int 3;
//_asm mov eax, result;
cout << "\nResult from library: " << result;
#else
cout << "\nloading FibAsmLib\n";
hDll = LoadLibrary("FibAsmLib");
cout << "loaded\n";
The asm part works in principle, i.e. it does return with eax==111111111, and the stack is balanced, but it doesn't do anything useful:
myAsmProc proc uses ecx edx esi edi ebx pA, B, pAlfa, beta, n ; double** A, double* B, double** alfa, double* beta, int n)
mov esi, pA
mov eax, 111111111
ret
Main.cpp, library and asm source are attached. Hope it helps ;-)
That static lib works perfectly, but I read once again requirements of my project and I must use dynamic library (dll) compiled in visual studio, so I returned to your code(that one from reply #9), I put it to my fibAsm.asm file inside of FibAsmLib project, I compiled it then I corrected 5 milion errors and in the end VS built it, but when i try to call that dll it throws my fauvorite error:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
This error sais: "Something is wrong find it and correct it because we dont give an shit"
Do you have an Idea what's causing it?
I am starting to hate everything connected with this project, so much that I will start to write error messages for MS :greensml:
Quote from: pawkondr on January 18, 2015, 12:25:21 AMThat static lib works perfectly, but ... a function declared with one calling convention with a function pointer declared with a different calling convention.
The problem is your declaration of DllFunc, probably hidden somewhere in the headers. I bet it is ccall.
So, attached the original DLL as CCALL, with source in RTF format. It should work, but test yourself - my VS throws that stupid error msvcrt120.dll not found. For a LoadLibrary call, good grief :eusa_boohoo:
How to tell compiler that the call convenction is ccall? I had _stdcall it didn't work, i deleted _stdcall, also didn't work. I tried to add something like this _ccall. Errors.
typedef int(_stdcall *DLLFunc)(double**, double*, double**, double*, int);
Or maybe is not that line or sth?
Compiling that dll in C someone can have easily exported names as excepted.
In cpp mangled names exists in dll like:
?fnFibAsmLib@@YAHXZ
?fnFibAsmLib@@3HA
pawkondr,
use the following declaration in the header file FibAsmLib.h:
extern "C" FIBASMLIB_API int __cdecl MyProc(double** A, double* B, double** alfa, double* beta, int n);
The ASM file is:
.686
.xmm
.model flat, C
PREAL8 typedef ptr REAL8
.code
MyProc proc C A: ptr PREAL8, B: ptr REAL8, alfa: ptr PREAL8, beta: ptr REAL8, n: SDWORD
; ...
mov eax, 5
ret
MyProc endp
end
then
- add the project directory FibAsmLib to the include paths of project Przyklad
- add library to linker input: "$(OutDir)FibAsmlib.lib"
- do not forget to set configuration == win32.
- include FibAsmLib.h into main.cpp and call MyProc directly (means: do not use GetProcAddress)
Quote from: qWord on January 18, 2015, 03:33:10 AMcall MyProc directly (means: do not use GetProcAddress)
Quote from: pawkondr on January 18, 2015, 12:25:21 AM
That static lib works perfectly, but I read once again requirements of my project and I must use dynamic library (dll)
Solution is to use somealgo proc
C in assembler, and something like this in C++ (tested, it works):
if (hDll != NULL){
myAsmProc = (DLLFunc)GetProcAddress(hDll, "myAsmAlgo");
cout << "GetProcAddress = " << myAsmProc << "\n";
if (myAsmProc != NULL)
result = myAsmProc(arrayA, arrayB, arrayAlfa, arrayBeta, rowA);
else
result = -1;
cout << "Result from dll: " << result;
cout << "\nFreeLibrary result is " << FreeLibrary(hDll);
}
Quote from: jj2007 on January 18, 2015, 04:29:06 AM
Quote from: qWord on January 18, 2015, 03:33:10 AMcall MyProc directly (means: do not use GetProcAddress)
Quote from: pawkondr on January 18, 2015, 12:25:21 AM
That static lib works perfectly, but I read once again requirements of my project and I must use dynamic library (dll)
Solution is to use somealgo proc C in assembler.
?
See above - teacher wants him to use LoadLibrary 8)
Attention: I lost one hour chasing a "bug" that consisted simply in believing current directory is where main.cpp sits. Nope, VS expects the DLL in the debug and/or release folders.
Quote from: jj2007 on January 18, 2015, 04:44:29 AM
See above - teacher wants him to use LoadLibrary 8)
then he just has to use something like:
typedef int(__cdecl * DLLFunc)(double** A, double* B, double** alfa, double* beta, int n);
...
hDll = LoadLibrary("FibAsmLib");
if (hDll != NULL){
DLLFunc myAsmProc;
myAsmProc = (DLLFunc)GetProcAddress(hDll, "MyProc");
if (myAsmProc != NULL){
result = myAsmProc(arrayA, arrayB, arrayAlfa, arrayBeta, rowA);
}
}
Quote from: qWord on January 18, 2015, 04:56:02 AMthen he just has to use something like
Yes indeed, see reply #6. The problem is not so much the declaration but that this giant "project" is scattered over 100 MB in 200+ files in akward locations and so occasionally one may lose the overview where the valid DLL version was placed, and where which version of the "project" expects it to be (hint:release and debug have their own respective paths).
Quote from: jj2007 on January 18, 2015, 05:09:29 AM
Quote from: qWord on January 18, 2015, 04:56:02 AMthen he just has to use something like
Yes indeed, see reply #6. The problem is not so much the declaration but that this giant "project" is scattered over 100 MB in 200+ files in akward locations
Most of this files are generated by the IDE, the actual project has just 15 files. The large files are for the autocomplete-database and the precompiled headers. You can delete most of these generated files and folders (debug, release, precompiled headers) before sharing to reduce the project size to some KB.
Quote from: jj2007 on January 18, 2015, 05:09:29 AMoccasionally one may lose the overview where the valid DLL version was placed, and where which version of the "project" expects it to be (hint:release and debug have their own respective paths).
the output of the projects is placed in the same directory after building - not that complicated.
Quote from: qWord on January 18, 2015, 05:29:59 AMthe output of the projects is placed in the same directory after building - not that complicated.
I meant the input files, i.e. the DLL. Anyway, new set of files attached. Place in the folder where main.cpp sits, i.e. Przyklad
hDll = LoadLibrary("..\\Przyklad\\Asm2Cpp.dll");
cout << "loaded, hDll=" << hDll << "\n";
if (hDll != NULL){
myAsmProc = (DLLFunc)GetProcAddress(hDll, "myAsmAlgo");
cout << "GetProcAddress = " << myAsmProc << "\n";
if (myAsmProc != NULL)
result = myAsmProc(arrayA, arrayB, arrayAlfa, arrayBeta, rowA);
else
result = -1;
cout << "Result from dll: " << result;
cout << "\nFreeLibrary result is " << FreeLibrary(hDll);
Each project has its own debug/release/(what ever other configuration) folder, but after building the output is copied to the corresponding folder of the project solution. So there is no need for relative path, because the DLL and the EXE are in the same directory after building.
The problem is that he passes wrong parameters. In the screen below you can see that n value is 0. And when I want to print that array on screen:
for (int i = 0; i < rowA; ++i){
for (int j = 0; j < rowA; ++j){
cout << arrayAlfa[i][j] << endl;;
}
}
That runtime error occures. Maybe i am doing something forbidden?
I also changed to this line:
typedef int(__cdecl * DLLFunc)(double** A, double* B, double** alfa, double* beta, int n);
(http://www.img.pl/KbMg.png)
Quote from: pawkondr on January 18, 2015, 06:01:59 AM
The problem is that he passes wrong parameters.
Check the latest version posted above. No runtime errors, but it might well be that I misunderstand how the matrices are built. For now it seemed more important to get the build system running.
myAsmAlgo proc uses esi edi ebx pA, B, pAlfa, beta, n ; double** A, double* B, double** alfa, double* beta, int n)
mov esi, pA
mov esi, [esi] ; **matrix
mov edi, pAlfa
mov edi, [edi] ; **matrix
The ASM code is assuming a flat "2D" array, which is not correct.
Here is what I found:
I run program with your main.cpp and your dll, as you said no runtime errors but results are wrong. Here is screen:
(http://www.img.pl/pcMg.png)
Here are correct results from my c++ library, which i think works properly (Numbers below "Result from library"):
(http://www.img.pl/ncMg.png)
My professor requires from me my own dll so i put that MyAsmAlgo proc to my library and tried it. Errors are still there but there are diffrent values of parameters and n is correct -> 3 not 0 like before.
try this one
.686
.xmm
.model flat, C
PREAL8 typedef ptr REAL8
PVOID typedef DWORD
.code
option prologue: none
option epilogue: none
MyProc proc C uses esi edi ebx A: ptr PREAL8, B: ptr REAL8, alfa: ptr PREAL8, beta: ptr REAL8, n: SDWORD
; save nonvolatile registers
push esi
push edi
push ebx
push ebp
PUSHED = 4*DWORD
; load pointers
mov ebx, [esp + 1*PVOID + PUSHED] ; A
mov esi, [esp + 2*PVOID + PUSHED] ; B
mov edi, [esp + 3*PVOID + PUSHED] ; alfa
mov edx, [esp + 4*PVOID + PUSHED] ; beta
xor ebp,ebp
; for each row-pointer
xor ecx,ecx
.while ecx < [esp+5*PVOID + PUSHED] ; i < n
; for each value in current row
xor eax,eax
.while eax < [esp+5*PVOID + PUSHED] ; j < n
; 0 = default value
xorpd xmm0,xmm0
; if i != j
.if ecx != eax
; load A[i][j]
mov ebp,[ebx+ecx*PREAL8]
movsd xmm1,REAL8 ptr [ebp+eax*REAL8]
; load A[i][i]
mov ebp,[ebx+ecx*PREAL8]
movsd xmm2,REAL8 ptr [ebp+ecx*REAL8]
; avoid div. by zero
comisd xmm0,xmm2
je @err
; div A[i][j] by A[i][i]
divsd xmm1,xmm2
; change sign
subsd xmm0,xmm1
.endif
; store alfa[i][j]
mov ebp,[edi+ecx*PREAL8]
movsd REAL8 ptr [ebp+eax*REAL8],xmm0
; next value
add eax,1
.endw
; load B[i]
movsd xmm0,REAL8 ptr [esi+ecx*REAL8]
; div B[i] by A[i][i]
mov ebp,[ebx+ecx*PREAL8]
divsd xmm0,REAL8 ptr [ebp+ecx*REAL8]
; store beta[i]
movsd REAL8 ptr [edx+ecx*REAL8],xmm0
; next row
add ecx,1
.endw
pop ebp
pop ebx
pop edi
pop esi
; indicate success (?)
xor eax,eax
retn
align 16
@err:
pop ebp
pop ebx
pop edi
pop esi
; indicate error (?)
mov eax,-1
retn
MyProc endp
end
(calling convention = __cdecl)
qWord, your code that you gave me works perfectly. Results are the same as it should be. No errors.
Thanks for your help qWord and jj2007. I will keep testing, writing and learning :)
Quote from: pawkondr on January 18, 2015, 09:06:12 AM
qWord, your code that you gave me works perfectly. Results are the same as it should be. No errors.
Thanks for your help qWord and jj2007. I will keep testing, writing and learning :)
You are welcome :icon14:
My code didn't work correctly because I had no time to find out how the matrices were constructed. I am glad that qWord's version works fine (he is a bright coder :t), but be aware that 1. your teacher can use Google, too and 2. you may have to explain to him how movsd, comisd, subsd etc work. You can find them in the Intel manuals under SIMD or SSE2. My code uses the FPU, which is a bit older but does the job perfectly. So how is this assembler experience for you? Will you come back from time to time and play with us, or will you stick to C/C++? ;)