C implementation for C++ strings & vector of strings - c++

I've some C++ APIs like below:
API1(std::string str, std::vector<std::string> vecofstr);
I want to call this API from a C code. How can i provide a C wrapper for this ?
std::string str
=>
I can probably use char* for std::string
&
std::vector<std::string> vecofstr =>
array of char* for vector of string like
char* arrOfstrings[SIZE];

This is what the corresponding C header (and its C++ implementation) could look like:
Declaration
#ifdef __cplusplus
extern "C"
#endif
void cAPI1(const char *str, const char * const *vecofstr, size_t vecofstrSize);
Implementation
extern "C" void cAPI1(const char *str, const char * const *vecofstr, size_t vecofstrSize)
{
API1(str, {vecofstr, vecofstr + vecofstrSize});
}
[Live example]
The above assumes that the C code will use zero-terminated strings for all string arguments. If that is not the case, the parameters of cAPI1 must be modified accordingly (ideally based on what representation of strings is actually used by the C code).

1.api.h
#ifndef API_H_
#define API_H_
#include <vector>
#include <string>
void api1(std::string& str, std::vector<std::string>& vecofstr);
#endif
.2. api.cpp
#include "api.h"
#include <iostream>
void api1(std::string& str, std::vector<std::string>& vecofstr) {
std::cout << str << std::endl;
for (size_t i=0; i<vecofstr.size(); i++) {
std::cout << vecofstr[i] << std::endl;
}
}
3.wrapper.h
#ifndef WRAPPER_H_
#define WRAPPER_H_
#define SIZE 2
#ifdef __cplusplus
extern "C" {
#endif
extern void wrapper1(char* p, char* [SIZE]);
#ifdef __cplusplus
};
#endif
#endif
4.wrapper.cpp
#include <string>
#include "wrapper.h"
#include "api.h"
#ifdef __cplusplus
extern "C" {
#endif
void wrapper1(char* p, char* ps[SIZE]) {
std::string str(p);
std::vector<std::string> vecofstr;
for (size_t idx=0; idx<SIZE; idx++) {
vecofstr.push_back(ps[idx]);
}
api1(str, vecofstr);
}
#ifdef __cplusplus
};
#endif
.5. test.c
#include "wrapper.h"
int main(void)
{
char* p = "hello world";
char* ps[] = {"world", "hello"};
wrapper1(p, ps);
return 0;
}
.6. compile
gcc -c api.cpp wrapper.cpp
gcc test.c -o test wrapper.o api.o -lstdc++
.7. run
./test
hello world
world
hello

Related

"multiple definition of" while variable is not defined anywhere else in the scope

I have these three source files:
test.h
#ifndef __TESTH
#define __TESTH
#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif
typedef struct {
uint8_t value;
} my_struct;
EXTERNC void initialise();
EXTERNC void load(my_struct**);
#endif
test.cpp:
#include <cstdint>
#include "test.h"
my_struct test;
void initialise() {
test.value = 200;
}
void load(my_struct** struct_ptr) {
*struct_ptr = &test;
}
main.cpp:
#include <cstdint>
#include <iostream>
#include "test.h"
my_struct *test;
int main() {
initialise();
load(&test);
while (true) {
std::cout << test->value << std::endl;
}
}
When I compile it, the linker gives me an error telling me that test has been defined multiple times (first defined in test.cpp).
Why? To me it seems like it doesn't leave the scope of test.cpp.
And when I remove the definition of test in main.cpp, it gives me an undefined error!
Thank you for taking the time out of your day to help me.
I think you would need to scope test.cpp's test variable to that file only, assuming your test pointer in main.cpp is different than test in test.cpp
namespace {
my_struct test;
}
See here

CGO, pass a struct from go to c++

I am experimenting with cgo, and wanted to use c++ with cgo. I found this post about doing it. If I have a c++ struct named Foo and a go struct named Foo, I want to pass the go Foo to c++. I tried doing this:
//bind.h
#ifdef __cplusplus
extern "C" {
#endif
#include "structs.hpp"
void bindCgo(Foo bar);
#ifdef __cplusplus
}
#endif
//structs.hpp
#ifndef STRUCTS_HPP_
#define STRUCTS_HPP_
typedef struct Foo {
#ifdef __cplusplus
std::string str;
#endif
}
#endif
//bind.cc
#include "structs.hpp"
using namespace std;
void bindCgo(Foo bar) {
cout << bar.str << endl; //this gives "sΘ\"
}
//main.go
import "unsafe"
// #cgo CFLAGS: -std=c99
// #include "bind.h"
import "C"
type Foo struct {
str string
}
func main() {
bar := Foo{""};
C.bindCgo(((*C.Foo)(unsafe.Pointer(&bar))))
}
Now when I run this program, it gives me sΘ\. Is this normal, and how can I fix this?
I also have maps and vectors in my struct so using char* will not work

Unsure how to decorate my C++ library code for use in C

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;
^
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 );
}
}

creating pl/sql tool using dll (c++ codes and DEV c++ compiler)

I am dealing with a dll project for my internship. I have to write a C++ code including some basic functions for pl/sql with dev c compiler and it must be work as a pl/sql tool.I wrote this codes.And i save the source file as dll file.I copied the dll extension file to plugin directory of pl/sql developer.It did not work.
Thank you all.
Here is my header and source code.
// header file plsqlHx.h
#ifndef _DLL_H_
#define _DLL_H_
#define DLL_EX
#include <string>
using namespace std;
extern "C" __declspec (dllexport) DLL_EX const char* IdentifyPlugIn(int);
extern "C" __declspec (dllexport) DLL_EX const char* CreateMenuItem(int);
extern "C" __declspec(dllexport) DLL_EX void OnMenuClick(int);
#endif
#include "plsqlHx.h"
#include <iostream>
#include <windows.h>
#include <string>
const char *const Desc = "C++Builder Plug-In demo 1";
int PlugInID;
const char* IdentifyPlugIn(int ID){
PlugInID = ID;
return Desc;
}
const char* CreateMenuItem(int Index){
switch (Index)
{
case 1 : return "Tools / &Plug-In 1 Demo...";
}
return "";
}
void OnMenuClick (int Index){
switch(Index){
case 11:
cout << "Hello";
break;
case 12:
cout << "Goodbye";
break;
}
}

Compiler acts as if a preprocessor directive isn't defined

I have a header file and its cpp file (Error.h, Error.cpp). The cpp file performs a check on a preprocessor directive but it always fails.
Error.h:
/*
Optional macros:
AE_EXIT_AT_ERROR
AE_CONSOLE_WRITE_AT_ERROR
*/
#pragma once
extern void aeError(const char *str, int code=1);
extern void aeAssert(bool b, const char *failStr = "assertion failed");
Error.cpp:
#include "Error.h"
#include <stdexcept>
#ifdef AE_CONSOLE_WRITE_AT_ERROR
#include <iostream>
#endif
void aeError(const char *str, int code)
{
#ifdef AE_CONSOLE_WRITE_AT_ERROR
std::cout << str << std::endl;
#endif
throw std::runtime_error(str);
#ifdef AE_EXIT_AT_ERROR
std::exit(code);
#endif
}
void aeAssert(bool b, const char *failStr)
{
if(!b)
aeError(failStr);
}
main.cpp:
//define both macros:
#define AE_CONSOLE_WRITE_AT_ERROR
#define AE_EXIT_AT_ERROR
#include "Error.h"
//rest of code
//...
both std::cout << str << std::endl; and std::exit(code); don't get compiled (I checked it "manually", although they are also marked gray by the IDE, which is VS2010).
What might be the cause of this?
main.cpp and Error.cpp are different translation units. You define the macro only for main.cpp, not for Error.cpp.
You should either put your #define directives in a header file included by both .cpp files, or define these macros in project settings/makefile.