views:

376

answers:

4

Possible Duplicate:
Convert some code from C++ to C

I've got some code that appears to be straight C. When I tell the compiler (I'm using Visual Studio 2008 Express) to compile it as c++, it compiles and links fine. When I try to compile it as C, though, it throws this error:

1>InpoutTest.obj : error LNK2019: unresolved external symbol _Out32@8 referenced in function _main
1>InpoutTest.obj : error LNK2019: unresolved external symbol _Inp32@4 referenced in function _main

The code reads from and writes to the parallel port, using Inpout.dll. I have both Inpout.lib and Inpout.dll. Here's the code:

// InpoutTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
/* ----Prototypes of Inp and Outp--- */

short _stdcall Inp32(short PortAddress);
void _stdcall Out32(short PortAddress, short data);

/*--------------------------------*/

int main(int argc, char* argv[])
{

 int data;

 if(argc<3)
 {
  //too few command line arguments, show usage
  printf("Error : too few arguments\n\n***** Usage *****\n\nInpoutTest read <ADDRESS> \nor \nInpoutTest write <ADDRESS> <DATA>\n\n\n\n\n");
 } 
 else if(!strcmp(argv[1],"read"))
 {

  data = Inp32(atoi(argv[2]));

  printf("Data read from address %s is %d \n\n\n\n",argv[2],data);

 }
 else if(!strcmp(argv[1],"write"))
 {
  if(argc<4)
  {
   printf("Error in arguments supplied");
   printf("\n***** Usage *****\n\nInpoutTest read <ADDRESS> \nor \nInpoutTest write <ADDRESS> <DATA>\n\n\n\n\n");
  }
  else
  {
  Out32(atoi(argv[2]),atoi(argv[3]));
  printf("data written to %s\n\n\n",argv[2]);
  }
 }



 return 0;
}

I previously asked this question, incorrectly, here.

Any help would be appreciated.

+5  A: 

It sounds like Inp32 and Out32 are defined externally in a C++ file/library, so you need to mark them as such so the compiler knows how their names will be mangled:

extern "C++" {
    short _stdcall Inp32(short PortAddress);
    void _stdcall Out32(short PortAddress, short data);
}
Michael Mrozek
That gives error C2059: syntax error : 'string'
Colin DeClue
Is there an `extern "C++"`? Could it be non-portable? I'd use `extern "C"`, in the header file where those functions are decared, with `#ifdef` guards so that only C++ compilers see it. C compilers already use C call conventions.
Steve314
@Steve There is, although it is much more common to do it the other way; I'm not sure about portability, as I've never actually needed to use it. If it's a library he doesn't control/have source for he doesn't have much choice though
Michael Mrozek
`extern C++` is portable C++, but it can't be used when compiling a C translation unit (since it's not C), so it's not appropriate in this particular situation. `extern "C++"` is only rarely useful - there are some C++ constructs that cannot be inside an `extern "C"` block, but you generally don't need to put them there anyway. See Microsoft's winnt.h for an example use of `extern "C++"`.
Michael Burr
@Michael - If he doesn't have the source, surely the thing to do is to write a small adapter library? Have C-linkage functions compiled in C++ that call the provided C++ functions.
Steve314
@Steve314 - you read my mind (see my overly-long answer).
Michael Burr
+2  A: 

It doesn't appear to be a compiler error, but rather a linker error. The linker can't find the definitions of Inp32 and Out32. Are you linking to the library that contains the definitions? Did you spell them correctly?

mipadi
The only thing I did was change the settings of the files to compile as C rather than C++. I didn't change any linking or anything. Is there something I need to change in the linker settings?
Colin DeClue
+6  A: 

You're trying to link to a C++ function, from C. That doesn't work due to name mangling- the linker doesn't know where to look for your function. If you want to call a C function from C++, you must mark it extern "C". C does not support extern "C++"- as far as I know. One of the other answers says there is. Alternatively, recompile it's source code as C.

Edit: Why ever would you compile as C if you could compile as C++, anyway?

DeadMG
I need to make the calls to Out32 from a C project which throws a bunch of errors if I try to compile as C++.
Colin DeClue
I recompiled the source for the lib as C, and it worked. (After I changed a reference from afxres.h to winres.h)
Colin DeClue
+5  A: 

If you need to call a C++ routine from C code, then the C++ routine need to have "C" linkage, which is done by marking the function as extern "C". That needs to be done on the C++ side.

Put the following as the prototypes for Inp32() and Outp32() if you're able to change the existing C++ code. This should be in a header that's included by whatever calls or defined the Inp32() or Outp32() functions - whether C or C++ code:

#ifdef __cplusplus
extern "C" {
#endif

short _stdcall Inp32(short PortAddress);
void _stdcall Out32(short PortAddress, short data);

#ifdef __cplusplus
}
#endif

That will mark those functions as having a C calling convention, and those functions will be callable by either C or C++ code.

If you don't have the ability to change the C++ code, you can create your own C-compatible wrappers for the C++ functions in your own C++ module:

The wrappers.h header file:

// in wrappers.h

// C-callable wrappers

#ifndef WRAPPERS_H
#define WRAPPERS_H

#ifdef __cplusplus
extern "C" {
#endif

short Inp32_wrapper( short PortAddress);
void Out32_wrapper( short PortAddress, short data);    

#ifdef __cplusplus
}
#endif

#endif /* WRAPPERS_H */

And, the wrappers.cpp implementation:

// in wrappers.cpp file:

#include "wrappers.h"

// prototypes for the C++ functions - these really should be in a
//  header file...

short _stdcall Inp32(short PortAddress);
void _stdcall Out32(short PortAddress, short data);

// implementation of the wrappers

short Inp32_wrapper( short PortAddress)
{
    return Inp32( PortAddress);
}

void Out32_wrapper( short PortAddress, short data)
{
    Out32( PortAddress, data);
}

Now your C code can #include "wrappers.h" and call the wrapper functions which will simply call the existing C++ functions to do the work.

Michael Burr