-2

We have defined some methods to allow for ad-hoc console input when required. The methods are contained within a namespace and define and use a class to perform the actual work.

The definions, stripped down for brevity:

ConsoleInput.h

#include <cstddef>
#include <map>
#include <memory>
#include <vector>

namespace MyNameSpc
{

typedef std::vector<char> buffer_t;

class ConsoleInput
{
// Methods for windows and linux console input
}

int GetString(buffer_t &buffer, ...);

}

RequestInput.h

#include "ConsoleInput.h"
#include <cstddef>
#include <string>

namespace MyNameSpc
{

const std::string empty = std::string();

class RequestInputParam
{
// Methods
}

int RequestInput(buffer_t &buffer);
int RequestInput(buffer_t &buffer, const RequestInputParam &param);
// and other overloads
}

ConsoleInput.cpp

#include "ConsoleInput.h"
#include "RequestInput.h"
#include <cstddef>
#include <iostream>
#include <memory>
#include <string>
#include <fcntl.h>
#include <stdio.h>
// and other headers.

namespace MyNameSpc
{
// implements class ConsoleInput methods.
// Implements GetString()
}

RequestInput.cpp

#include "ConsoleInput.h"
#include "RequestInput.h"
#include <cstddef>
#include <iostream>
#include <memory>
#include <string>

namespace MyNameSpc
{
// implements the overloaded methods.
}

And we call them by #include RequestInput.h and then calling int retVal = MyNameSpc::RequestInput(...). This all works fine when all of the code is C++. I now have to reference this code from C code which was recently dropped into our repository. I don't think I can (well, I -can-, but I think it's going to break other things) simply compile the C code as C++, so I really do need to somehow pull this into C.

When I tried to build, I was getting initial errors about not finding the iostream header.. makes sense, but, after reading about extern "C", I am unclear how to proceed, when I have these C++ headers in the code, classes (the only one I might need to reference is the parameter class) and namespaces.

UPDATE

I have reviewed the links which were provided and attempted to make use of the information from here and here. I am having no success with this.

RequestInputWrapper.h

#ifndef REQUEST_WRAPPER_H
#define REQUEST_WRAPPER_H

#include <stddef.h>
#include "RequestInput.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct RequestInputParam RequestInputParam; // line 29

RequestInputParam* CreateRequestInputParam();
void DisposeRequestInputParam( RequestInputParam* pObject );

void C_AddMainPrompt(RequestInputParam *param, char *msg);

int C_RequestInputAllocPtr(char * * const ppInput,
                           unsigned int * const pInputLen);

int C_RequestInput(char * const pInput,
                   unsigned int * const pInputLen);

#ifdef __cplusplus
}
#endif

#endif   /* REQUEST_WRAPPER_H */

RequestInputWrapper.cpp

#include "RequestInput.h"
#include "RequestInputWrapper.h" // line 13

#ifdef __cplusplus
extern "C" {
#endif

RequestInputParam* CreateRequestInputParam()
{
    return new RequestInputParam();   // line 25
}

void DisposeRequestInputParam( RequestInputParam* pObject ) // line 28
{
    if ( pObject != NULL )
    {
        delete pObject; // line 32
        pObject = NULL;
    }
}

void C_AddMainPrompt(RequestInputParam *param, char *msg)          { param->AddMainPrompt( msg ); }

int C_RequestInputAllocPtr(char * * const ppInput,
                           unsigned int * const pInputLen)
{
    return RequestInput(ppInput, pInputLen);
}

int C_RequestInput(char * const pInput,
                   unsigned int * const pInputLen)
{
    return RequestInput(pInput, pInputLen);
}

#ifdef __cplusplus
}
#endif

It is currently throwing the following errors (I C&P only the first portion, it started getting repetitive; the line numbers won't match the code above, which has been stripped of all comments and such so I added comments with the noted line #'s):

cli/RequestInputWrapper.cpp: In function ‘RequestInputParam* CreateRequestInputParam()’:
cli/RequestInputWrapper.cpp:25:35: error: invalid use of incomplete type ‘RequestInputParam {aka struct RequestInputParam}’
     return new RequestInputParam();
                                   ^
In file included from cli/RequestInputWrapper.cpp:13:0:
./Include/RequestInputWrapper.h:29:16: error: forward declaration of ‘RequestInputParam {aka struct RequestInputParam}’
 typedef struct RequestInputParam RequestInputParam;
                ^
cli/RequestInputWrapper.cpp: In function ‘void DisposeRequestInputParam(RequestInputParam*)’:
cli/RequestInputWrapper.cpp:32:16: error: possible problem detected in invocation of delete operator: [-Werror]
         delete pObject;
                ^
cli/RequestInputWrapper.cpp:28:6: error: ‘pObject’ has incomplete type [-Werror]
 void DisposeRequestInputParam( RequestInputParam* pObject )
      ^
In file included from cli/RequestInputWrapper.cpp:13:0:
./Include/RequestInputWrapper.h:29:16: error: forward declaration of ‘struct RequestInputParam’ [-Werror]
 typedef struct RequestInputParam RequestInputParam;
                ^
cli/RequestInputWrapper.cpp:32:16: note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined
         delete pObject;
                ^
Jon
  • 1,675
  • 26
  • 57
  • 1
    You need to create global (non-namespace) function wrappers (declared `extern "C"`) that call your C++ functions. – Some programmer dude Oct 11 '18 at 14:50
  • 1
    Possible duplicate of [Developing C wrapper API for Object-Oriented C++ code](https://stackoverflow.com/questions/2045774/developing-c-wrapper-api-for-object-oriented-c-code) – Mike Kinghan Oct 12 '18 at 15:27

1 Answers1

-1

I suspect the answers in the articles suggested as "duplicates" have simply been written and not tested. After more searching, I eventually stumbled across this answer which offered the guidance needed to get this to build.

In short, I was missing the namespace in my C++ wrapper code (facepalm) and I had to add the reinterpret_cast calls. I also changed the name of the type in the typedef... I thought it was referencing the C++ type (as that was what at least one example seemed to show) but, nope... it needs to be it's own struct type.

RequestInputWrapper.h

#ifndef REQUEST_WRAPPER_H
#define REQUEST_WRAPPER_H

#ifdef __cplusplus
extern "C" {
#endif

#include <stddef.h>

typedef struct C_RequestInputParam C_RequestInputParam;

C_RequestInputParam * CreateRequestInputParam();
void DisposeRequestInputParam( C_RequestInputParam *pObject );

void C_AddMainPrompt( C_RequestInputParam *param, char *msg);

int C_RequestInputAllocPtr( char * * const ppInput,
                           unsigned int * const pInputLen );

int C_RequestInput( char * const pInput,
                    unsigned int * const pInputLen );

#ifdef __cplusplus
}
#endif

#endif   /* REQUEST_WRAPPER_H */

RequestInputWrapper.cpp

#include "RequestInput.h"
#include "RequestInputWrapper.h"

extern "C" {

C_RequestInputParam * CreateRequestInputParam()
{
    return reinterpret_cast< C_RequestInputParam * >( new RequestInputParam() );
}

void DisposeRequestInputParam( C_RequestInputParam *pObject )
{
    if ( pObject != NULL )
    {
        delete reinterpret_cast< MyNameSpc::RequestInputParam * >( pObject );
        pObject = NULL;
    }
}

void C_AddMainPrompt( C_RequestInputParam *param, char *msg )
{
    reinterpret_cast< MyNameSpc::RequestInputParam * >( param )->AddMainPrompt( msg );
}

int C_RequestInputAllocPtr( char * * const ppInput,
                            unsigned int * const pInputLen )
{
    return MyNameSpc::RequestInput( ppInput, pInputLen );
}

int C_RequestInput( char * const pInput,
                    unsigned int * const pInputLen )
{
    return MyNameSpc::RequestInput( pInput, pInputLen );
}

}
Jon
  • 1,675
  • 26
  • 57