Click here to Skip to main content
15,887,135 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Dear experts,

in a C++/CLI project I have a native Logging class with a virtual variadic member function 'Write'. Furthermore, I have a global __LOG variable that holds an instance of that class.

If I call '__LOG.Write(1,"%f",8.34)' from main, it displays the floating point value correctly.

However, if I call '__LOG.Write(1,"%f",8.34)' from a member function of a managed class, the function displays 0.00000. To get the expected output, I need to change the 'Write' function to a non-virtual function.

Can somebody explain this behavior?


// compiled with /clr
#include <cstdarg>
#include <iostream> 

#pragma unmanaged
class NativeLog
{
public:
	virtual void Write(int aLogType, const char* aFormat, ...) const
	{
		char str[128];

		std::va_list args;
		va_start(args, aFormat);
		vsprintf_s(str, 128, aFormat, args);
		va_end(args);

		std::cout << str << std::endl;
	}
};

// Global unmanaged log object
NativeLog __LOG;

#pragma managed

ref class ManagedCaller
{
public:
	void Call() { __LOG.Write(1, "%f", 8.34); }
};

int main()
{
	__LOG.Write(1, "%f", 8.34);
	(gcnew ManagedCaller())->Call();

	return 0;
}


What I have tried:

The issue came up in a larger project, and I have isolated it to the code above. I don't need help with the design. I just want to understand the behaviour.
Posted

1 solution

The varargs does not supported under clr. Yes you can use it without problem with unmanaged code but on managed it has the underlaying type as System::Double or System::Int32 which unable to properly transmit as variadic argument. You can create intermediate method which will performs string formatting String::Format() and pass resulted string into your function.
char* s = (char*)(void*)Marshal::StringToHGlobalAnsi(String::Format("{0}",8.34));
__LOG.Write(1,s);
Marshal::FreeHGlobal((IntPtr)s);

Regards,
Maxim.
 
Share this answer
 
Comments
SchmitzeMarc 1-Dec-23 5:54am    
Dear Maxim, thank you for your response. However, the vararg seems to have no problem as long as I declare the 'Write' method as non-virtual. Do you have an idea why it makes a difference whether or not the 'Write' function is declared virtual?
Maxim Kartavenkov 1-Dec-23 6:34am    
I had checked your code with virtual and non-virtual your Write method declaration and it works the same way to me, but I didn't setup pragma managed or unmanaged as I just put your code into existing project and check. The issue I found that on some varargs types it provides the wrong memory address from va_start. After just found that MS specify that they not support varargs on clr. So the issue appear on the place whre the code executed on managed space - managed type specified - address invalid. You can test that in next way: set breakpoint after va_start then switch into memory view, specify variable "args" and select view type based on type you provide on input.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900