Вызов функции C ++ из C для возврата char * - PullRequest
0 голосов
/ 17 декабря 2018

При написании UDF в MySQL я застрял при вызове функции c ++ из c, которая должна возвращать char *.Я пробовал:

encrypt.cpp

string encrypt(string Data)
{
   ...
   //some encryption logic
   ...
   return encryptStr; //encryptStr is string 
}

Для вызова вышеуказанной функции из c, я использую extern c в том же файле, что и:

extern "C" char * c_encrypt(char *bar)
{
    std::string str = encrypt(std::string(bar));
    return what_to_do_to_return_char*;
}

UDF.c

char* Encrypt_UDF( UDF_INIT* initid, UDF_ARGS* args, char* result, unsigned long* length, char* is_null, char* error )
{
    const char* arg = args->args[0];
    char * encryptData = c_encryt(arg); //calling c_encrypt()        
    return encryptData ;
}

Итак, что я должен сделать в c_encrypt(), чтобы вернуть char *?

Ответы [ 2 ]

0 голосов
/ 17 декабря 2018

Чтобы вернуть char * из строки C ++ в целом, вы должны сделать:

char *c = (char*)malloc(str.size() + 1);
strcpy(c, str.c_str());
return c;

Обратите внимание, что вызывающая сторона должна освободить память, на которую указывает char *.

0 голосов
/ 17 декабря 2018

Согласно документации MySQL ваша функция должна иметь следующий прототип:

extern "C" char *encrypt(UDF_INIT *initid, UDF_ARGS *args,
      char *result, unsigned long *length,
      char *is_null, char *error);

Тогда вам следует использовать параметры result и length, чтобы "вернуть" вашу строку, если онаумещается в 255 байтов (согласно этой странице документации):

extern "C" char *encrypt(UDF_INIT *initid, UDF_ARGS *args,
      char *result, unsigned long *length,
      char *is_null, char *error)
{
    std::string str = encrypt_impl(args->args[0]);
    strcpy(result, str.c_str());
    *length = str.size();
    return result;
}


В случае, если ваша строка не всегда умещается в 255 байтов, вам нужно выделить буфердля себя и, что более важно, освободите его, чтобы избежать утечек памяти .Для этого вам нужно будет реализовать дополнительные функции encrypt_init и encrypt_deinit, как описано здесь , и определить структуру данных, которую вы будете использовать для совместного использования ресурса всеми тремя функциями:
struct EncryptData
{
    std::string encryptedStr;
};

extern "C" bool encrypt_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
    /* Use non-throwing allocation because there is no one to catch the exception */
    initid->ptr = (char *) new (std::nothrow) EncryptData();

    /* Return false if allocation failed */
    if (!initid->ptr)
        return false;
    return true;
}

extern "C" void encrypt_deinit(UDF_INIT *initid)
{
    delete (EncryptData *) initid->ptr;
}

extern "C" char *encrypt(UDF_INIT *initid, UDF_ARGS *args,
      char *result, unsigned long *length,
      char *is_null, char *error)
{
    EncryptData *data = (EncryptData *) initid->ptr;
    data->encryptedStr = encrypt_impl(args->args[0]);

    /* Can't return c_str() here, since the return type is non-const */
    return &data->encryptedStr[0];
}

Вы также можете использовать initid->ptr для самого строкового буфера, как предлагалось здесь с использованием комбинации malloc/realloc/free, но я думаю, что всегда лучше использовать struct или даже class в качестве общегошаблон для совместного использования общего контекста между несколькими функциями.

Также обратите внимание, что функцию encrypt можно вызывать несколько раз (для каждой строки), а encrypt_deinit будет вызываться только один раз (для каждой инструкции SQL), поэтомуВы должны освободить или повторно использовать предыдущий буфер в encrypt перед выделением нового.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...