Linker error when calling a C function from C++ code in different VS2010 project
Asked Answered
D

1

0

I'm trying to include some C code I found in our C++ project. The function is defined like this in the C file.

#ifdef __cplusplus
extern "C" {
#endif
 extern char *dtoa(double, int, int, int *, int *, char **);
 extern char *g_fmt(char *, double);
 extern void freedtoa(char*);
#ifdef __cplusplus
    }
#endif

 char *
g_fmt(register char *b, double x)
{

The VS project I'm including this in is creating a dll. The file is being compiled as C, other files in the project are being compiled as C++.

I added a header to include in my C++ files

#ifndef G_FMT_H
#define G_FMT_H
#ifdef __cplusplus
extern "C" {
#endif
 extern char *dtoa(double, int, int, int *, int *, char **);
 extern char *g_fmt(char *, double);
 extern void freedtoa(char*);

#ifdef __cplusplus
}
#endif
#endif //G_FMT_H

In another project in the solution I include my header and try calling the g_fmt function.

#include "header.h"
...
g_fmt(my_array, 2.0);

This project is linking to the other one, I'm able to call C++ functions in the first library without any issues. However, adding the above line gives me a lnk2001 error .

error LNK2001: unresolved external symbol g_fmt

I've found a number of other questions about mixing C and C++ and I seem to have done everything necessary with the extern keywords in the right places, however I'm still not able to link. Is there anything specific I need to do in VS2010?

Dimmick answered 1/6, 2015 at 19:38 Comment(4)
so you can use dtoa but not g_fmt?Woodring
no, I mean I can use C++ functions declared elsewhere in the same library. I've read in other posts you can mix C and C++ in the same project, maybe that isn't quite true?Dimmick
It's true, the point is how do you export functions? Usually you need a __declspec(dllexport) or a def file. What method do you use here?Woodring
The linker is looking for the actual function's object code (or import library stub). It isn't looking at header files or C++ source code -- the compilation stage has passed. So where is the g_fmt function actually implemented? Is it in a library?Herschel
A
4

The question is for VStudio 2010, but applies to any version.

In C or C++, considering that a module may consist of multiple objects, every object should be clearly delimited. Also, every object (.c or .cpp file) should have its own header file. So, you should have one header file and one .c(xx) file for the C functions (3 in your example).
Also, as a general guideline, try to be consistent when naming files and macros: your header.h file uses G_FMT_H macro as include guard.
Try reorganizing your .h and .c files to something like:

  • functions.h:

    #pragma once
    
    #if defined(_WIN32)
    #  if defined(FUNCTIONS_STATIC)
    #    define FUNCTIONS_EXPORT_API
    #  else
    #    if defined(FUNCTIONS_EXPORTS)
    #      define FUNCTIONS_EXPORT_API __declspec(dllexport)
    #    else
    #      define FUNCTIONS_EXPORT_API __declspec(dllimport)
    #    endif
    #  endif
    #else
    #  define FUNCTIONS_EXPORT_API
    #endif
    
    #if defined(__cplusplus)
    extern "C" {
    #endif
    
    FUNCTIONS_EXPORT_API char *dtoa(double, int, int, int*, int*, char**);
    FUNCTIONS_EXPORT_API char *g_fmt(char*, double);
    FUNCTIONS_EXPORT_API void freedtoa(char*);
    
    #if defined(__cplusplus)
    }
    #endif
    
  • The corresponding implementation (functions.c):

    #define FUNCTIONS_EXPORTS
    #include "functions.h"
    
    
    char *dtoa(double, int, int, int*, int*, char**)
    {
        //function statements
    }
    
    
    char *g_fmt(char*, double)
    {
        //function statements
    }
    
    
    void freedtoa(char*)
    {
        //function statements
    }
    

2 things to notice here (besides reorganizing and renaming) in the header file:

  • The extern storage specifier for each function is gone

  • Exporting logic: your project will define now FUNCTIONS_EXPORT (from functions.c, or desirable to be a VStudio project setting - anyway, somewhere before #include "functions.h")

    • When this project (functions.c) will be compiled, the functions will be exported (due to the macro definition)

    • When the header file will be included in another project (that doesn't define FUNCTIONS_EXPORTS), the functions will be marked as imported, and the linker will search for them in the imported .lib(s) - one of them should be the one generated by this project

    • To be more rigorous, you could replace the FUNCTIONS_EXPORTS (and remove its definition from functions.c) by a macro that's automatically defined by VStudio IDE: ${YOUR_PROJECT_NAME}_EXPORTS (e.g. if your Dll project is called ExportFunctionsProject.vc(x)proj, then the macro name will be EXPORTFUNCTIONSPROJECT_EXPORTS)

    • You can check the macro name in VStudio (2010) IDE: Project Properties -> C/C++ -> Preprocessor -> Preprocessor definitions. For more details, check [MS.Docs]: /D (Preprocessor Definitions)

Similar (or related) issues:

Accumulation answered 1/6, 2015 at 21:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.