2

I am calling a function documented as follows:

int BIO_write_filename(BIO *b, char *name)

with the following:

std::string filename{"myfile"};
if (BIO_write_filename(bio, filename.c_str()) <= 0) {
    throw std::runtime_error{"Could not prepare output file.\n"};
}

But I get the following error: cannot convert argument 4 from 'const char *' to 'void *'

I discovered that I'm actually dealing with a macro:

# define BIO_write_filename(b,name) BIO_ctrl(b,BIO_C_SET_FILENAME, BIO_CLOSE|BIO_FP_WRITE,name)

So what I'm actually calling is:

long BIO_ctrl(BIO *bp, int cmd, long larg, void *parg);

What is the best way to call this from C++?

So far I'm considering the following two options:


Option 1: c-style cast:

BIO_write_filename(bio, (void*)filename.c_str())

Option 2: C++ type cast:

const void* filename_ptr_c{(filename.c_str())};
void* filename_ptr{const_cast<void*>(filename_ptr_c)};
BIO_write_filename(bio, filename_ptr)
wally
  • 10,717
  • 5
  • 39
  • 72
  • 1
    If you are using OpenSSL with C++, then see [unique_ptr and OpenSSL's STACK_OF(X509)*](http://stackoverflow.com/q/38145761) and [How to get PKCS7_sign result into a char * or std::string](http://stackoverflow.com/a/38079093/608639) for some more techniques. – jww Jul 12 '16 at 21:27
  • 1
    *"... but I get the following error: `cannot convert argument 4 from 'const char *' to 'void *'`"* - that sounds like an OpenSSL bug since they try to support average or typical C++ use cases. – jww Jul 12 '16 at 21:50
  • @jww If not a bug then it might be described as an inconsistency. In [`bio.h`](https://github.com/openssl/openssl/blob/master/include/openssl/bio.h) we have `(char *)name` for `BIO_read_filename`'s paramater, but only `name` for `BIO_write_filename`'s parameter. I'm not confident enough to report this as a bug yet... :) – wally Jul 13 '16 at 17:07

2 Answers2

1

My suggestion:

BIO_write_filename(bio, const_cast<char*>(filename.c_str()));
R Sahu
  • 204,454
  • 14
  • 159
  • 270
1

In answer to your question. Use C++ style casts. They were added to C++ because C++ style casts to supersede C-Style casts. You can read more about the justification for C++ casts here: https://softwareengineering.stackexchange.com/questions/50442/c-style-casts-or-c-style-casts

As a bonus though, I'd suggest you eliminate the macro. As you have seen macros are a toxic element in C++. A vast improvement over either of your options would be:

if(BIO_ctrl(bio, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_WRITE, data(filename)) <= 0L)

This does use C++17's: data so if you don't have access to that feel free to just use the const_cast<char*> and allow the cast to void* to occur implicitly.

Community
  • 1
  • 1
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288