7

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];

4
  • 1
    hmm, the std::vector is passed in as a copy... Commented Sep 4, 2017 at 7:51
  • so yeah perhaps... Commented Sep 4, 2017 at 7:51
  • I would use: API1_Wrapper(const char* str, const char** vecofstr, size_t vecSize); Commented Sep 4, 2017 at 7:54
  • ^ that, wrapped in extern "C" {}. Commented Sep 4, 2017 at 7:54

2 Answers 2

19

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).

Sign up to request clarification or add additional context in comments.

14 Comments

There is an assumption here that str and the elements of vecofstr are all C-strings (i.e. terminated with a character with value zero). Otherwise, your code yields undefined behaviour.
I'm trying to understand the syntax: {vecofstr + vecofstrSize} in the C implementation. How can this be assigned to the vector::string in C++ counterpart ?
@codeLover - If you aren't sure how is it allowed to initialize a vector, your first stop should be the documentation of std::vector's constructors
@codeLover Note that as the answer says, the function cAPI1 needs a C++ implementation, not a C one. The syntax is {vec, vec + size}, which simply invokes the 2-iterator constructor of std::vector.
In modern C you would rather write void cAPI1(const char *str, const, size_t vSize, char* vecofstr[vSize]). Pointer-to-pointer usually indicates that you intend to return a pointer, so it is misleading.
|
-3

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.