Hi folks,

I am writing an application in C, but I have the OOP functionality that C++ provides. (i.e., I can only use C library functions).
I have a function as follows in TSL1.cpp:

void TSL1_ExecuteTest (char *sCmdInt[])
/*******************************************************************************

	Name:			TSL1_ExecuteTest
					
	Description:	      This function executes tests from current TSL1 board file.
					
	Inputs:			char *sCmdInt[] -- The command array
					
	Outputs:		None
********************************************************************************/
{
char returnData[256];
if ( sCmdInt[0] != NULL )
{
    if ((pTSL1_Commands = new CTSL1_Commands) != NULL)
    {
        pTSL1_Commands->TSL1_InitialiseBoard();
	if (strcmp(sCmdInt[0], "ReadMemory32") == 0)
	    pTSL1_Commands->TSL1_ReadMemory32(sCmdInt, returnData);
    }
}

Now, in TSL1_Commands.cpp I have:

int CTSL1_Commands::TSL1_ReadMemory32 (char *sCmdInt[], char returnData[256])
/*******************************************************************************

	Name:			TSL1_ReadMemory32
					
	Description:	        This function handles the call to read memory 32
					
	Inputs:			sCmdInt - A pointer to the command array 
					
	Outputs:		returnData - The result from the command
********************************************************************************/
{
	int iError = DIAG_ReadMem32(sCmdInt[1], returnData);
	return iError;
}

In the function TSL1_ExecuteTest, a command will be passed to it and the relative function called. The problem is, there are ~200 different commands which may be passed to it. So, I am trying to create a look up table to hold all the command names, so that I don't have to create an if/else structure for all the different commands.

I have created a structure as follows:

typedef int (*myfunction)(char *[], char[]);
struct
{
    myfunction thefunc;
    const char* functionName;
}
lookUpTable[] = { {pTSL1_Commands->TSL1_ReadMemory32, "ReadMemory32"}, {NULL, NULL} };

For the moment, I have simply included it in the TSL1_ExecuteTest function. Errors are occurring as follows:

Compiling...
TSL1.cpp
C:\Projects\uMaster3xxxC++\IntelDriver\TSL1\TSL1.cpp(513) : error C2440: 'initializing' : cannot convert from '' to 'int (__cdecl *)(char *[],char [])'
None of the functions with this name in scope match the target type
C:\Projects\uMaster3xxxC++\IntelDriver\TSL1\TSL1.cpp(513) : error C2440: 'initializing' : cannot convert from 'char [13]' to 'int (__cdecl *)(char *[],char [])'
There is no context in which this conversion is possible
Error executing cl.exe.

TSL1.dll - 2 error(s), 0 warning(s)

Help?
1) Can anyone help with the errors/advise on better practice, or give me any other ideas as to what kind of structure to use?
2) If this struct is fine, where should I be declaring it (I know it probably shouldn't be in the middle of a function?)

Any help gladly received.

The problem is that pTSL1_Commands->TSL1_ReadMemory32 is a "method" not a "function". The difference is that a method has the implicit "this" pointer to the object passed to it, while a function only has the parameters of its prototype declaration.

So a function pointer, if you need to use one and not a function object, can only point to either a global or namespaced function, or a static member function. In either case, you cannot get the implicit "this" pointer passed, so you will have to make it an explicit parameter if you need it.

So in your case, if you have data inside TSL1_Commands and need that object in the code of your commands, then add a pointer to a TSL1_Commands object as the first parameter of your function pointer prototype, and make all the command functions "static". That should work, but, of course, it's a bit annoying and function objects would do much more nicely.

Edited 6 Years Ago by mike_2000_17: n/a

Hi, thanks for the guidance, it seems to make more sense now. I'm still having issues now (I think) using function instead of methods. The function is defined in another DLL as follows:

int __declspec(dllexport) __stdcall DIAG_ReadMem32 (LPSTR cMemAddr, LPSTR cReturnData)
/*******************************************************************************

	Name:			DIAG_ReadMem32
					
	Description:	This function reads 32-bit data from a UUT memory address.
					
	Inputs:			cMemAddr -- string specifying memory address to read 
					
	Outputs:		cReturnData -- string holding data read from address  
					return  0 -- no error
					return -1 -- function error
										
*******************************************************************************/
{
	int iError = 0;

	switch (iProcessor)
	{
	case ePentium4: // Willamette, Northwood and Xeon.
		iError = pPentium4->ReadMemory (32, cMemAddr, cReturnData);
		break;

	case eBanias: // Banias.
		iError = pBanias->ReadMemory (32, cMemAddr, cReturnData);
		break;



//      .....contd.
	default: // Error trapping.
		return -1;
	}

	return iError;
}

Now the look up table is constructed as follows:

{
....
	typedef int (*myfunction)(char *[], char[]);
	struct
	{
		myfunction thefunc;
		const char* functionName;
	}
	lookUpTable[] = { {DIAG_ReadMem32, "ReadMemory32"}, {NULL, NULL} };
....

I have created the required function pointers to DIAG_ReadMem32 and created the DLL handler, which works fine calling it independently, however, using it within the look up table produces the same compiler errors as before:


c:\projects\umaster3xxxc++\inteldriver\tsl1\tsl1.cpp(513) : error C2440: 'initializing' : cannot convert from '' to 'int (__cdecl *)(char *[],char [])'
None of the functions with this name in scope match the target type
c:\projects\umaster3xxxc++\inteldriver\tsl1\tsl1.cpp(513) : error C2440: 'initializing' : cannot convert from 'char [13]' to 'int (__cdecl *)(char *[],char [])'
There is no context in which this conversion is possible
Error executing cl.exe.

TSL1.dll - 2 error(s), 0 warning(s)

Any other suggestions?
You may have guessed by now, i'm really new at this :S

Well, two things I can say.

First, the error is because you didn't match the calling convention. In the DLL function, the keyword __stdcall sets the calling convention to the standard calling convention (which is needed for DLL exported functions, in most operating systems). But the default calling convention in C++ functions is __cdecl. So that is the error, it says the function DIAG_ReadMem32 is not __cdecl. So, to fix the problem, you have to declare the function pointer type as

typedef int __stdcall (*myfunction)(char *[], char[]);

Second, if all the functions that you need in the look-up table are from a DLL. Then, look at run-time loading of the DLL. This is because the DLL already has a look-up table in it, so you could use it instead of making your own on top of it. In linux, the commands are dlopen(), dlsym(), dlclose() to load a .so, get the function pointer by name (called symbol), and close the .so, respectively. In windows, the corresponding functions are LoadLibrary(), GetProcAddress(), CloseLibrary(). You can look those up by yourself.

Hi, i have already created the 'interfacing' between the two DLLs as follows:

typedef int (__stdcall* LPFunction1) (int, LPSTR, LPSTR, LPSTR);
LPFunction1 DIAG_SelectHardware;

hGetProcIDDLL = LoadLibrary("C:\\Windows\\System32\\UMASTER3XXXDPIL1.DLL");
if (hGetProcIDDLL != NULL)
{
    DIAG_SelectHardware = (LPFunction1)GetProcAddress(hGetProcIDDLL,"DIAG_SelectHardware");
}
....
// Release the Dll 
	FreeLibrary(hGetProcIDDLL);

How do I use this as a look up table instead of creating my own?

Thanks again, you've been most helpful.

Well, this line:

DIAG_SelectHardware = (LPFunction1)GetProcAddress(hGetProcIDDLL,"DIAG_SelectHardware");

Already is a look-up in a look-up table of the DLL. It looks in the look-up table of the DLL for the function corresponding to the name "DIAG_SelectHardware", and outputs the function pointer to it. So if all the functions you have are in that DLL, then that's all you need, forget about making a look-up table on top of that.

One remark, you do know that you should not call FreeLibrary until the very end, when there is no more chance that you might be calling any of the DLL functions again.

Yes, I actually have a long list of function pointers, and I'm handling it all in the de/constructor (including freeing the library). The problem is that the string that is passed in from the file is not exactly the same as the string corresponding to the function. For example, one command is "ReadMemory32", whereas the function name is "DIAG_ReadMem32".
Do this mean I will need to create my own?

Well if the names are mismatched, then you could implement your own look-up table. But there are two options to avoid it. First, you can change the name of the function in the DLL to match the command strings. Or second, you can export the functions from the DLL with a different name than their internal name in the DLL's implementation (i.e. an alias). Look at internalname vs. entryname, for example on the msdn page on EXPORTS and the module-definition file.

Of course, if you cannot touch the DLL's implementation, then you have no choice but to implement your own look-up table, as your original solution, and with the __stdcall fix it should work fine.

Mike,
thanks for all your help. You've been great explaining some of the concepts involved in this problem.
I have finally 'fixed' the issues as follows:

typedef int (_stdcall *myfunction)(char *, char *);
struct
{
    myfunction thefunc;
    const char* functionName;
}
lookUpTable[] = { {pTSL1_Commands->DIAG_ReadMem32, "ReadMemory32"}, {NULL, NULL} };

Just a few questions no re implementation.
1) Is is possible to put the struct in the header file, or would it be better in the constructor?
2) Can you advise on an efficient way of looping/indexing into it thereafter?
I have an example piece of C++ code which illustrates nicely a way to do it, but i'm unsure of how to get it done in C:

bool CallFunction(const string& functionName)
{
    for(int index = 0; lookUpTable[index].fn; index++)
    {
        if(functionName == lookUpTable[index].key)
        {
            (*(lookUpTable[index].fn))();
            return true;
        }
    }
return false;
} 

int main(int argc, char** argv)

{

CallFunction("FunctionOne");

CallFunction("FunctionTwo");

return EXIT_SUCCESS;

}

In my case, CallFunction would be equivalent to TSL1_ExecuteTest (char *sCmdInt[])

This article has been dead for over six months. Start a new discussion instead.