Как вернуть байты декодированного изображения base64 через формальный параметр метода типа char**

#c #dll #casablanca

#c #dll #касабланка

Вопрос:

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

Этот метод получает строку изображения в кодировке base64 из API. Метод должен следовать этой подписи, поскольку он является частью устаревшего кода, которому не разрешается сокращать то, как он был написан изначально. Таким образом, подпись должна оставаться неизменной. Кроме того, я опустил здесь асинхронные вызовы и продолжения, исключения и т. Д. Для простоты кода.

 int __declspec(dllexport) GetInfoAndPicture(CString uid, char **image, long *imageSize)
{
    CString request = "";
    request.Format(url); 

    http_client httpClient(url);
    http_request msg(methods::POST);

    ...

    http_response httpResponse;
    httpResponse = httpClient.request(msg).get();  //blocking
    web::json::value jsonValue = httpResponse.extract_json().get();

    if (jsonValue.has_string_field(L"img"))
    {
        web::json::value base64EncodedImageValue = jsonValue.at(L"img");
        utility::string_t imageString = base64EncodedImageValue.as_string();  
        std::vector<unsigned char> imageBytes = utility::conversions::from_base64(imageString);
        image = (char**)amp;imageBytes;  //Is this the way to pass image bytes back? 
    *imageSize = imageBytes.size();
    }

    ...
}
  

Вызывающий вызывает этот метод следующим образом:

 char mUid[64];
char* mImage;
long mImageSize;
...
resultCode = GetInfoAndPicture(mUid, amp;mImage, amp;mImageSize);

//process image given its data and its size
  

Я знаю, что такое указатель на указатель, мой вопрос относится к этой строке

 image = (char**)amp;imageBytes;
  

Является ли это правильным способом возврата изображения, декодированного из base64, в вызывающий код через char** image формальный параметр, учитывая вышеупомянутую сигнатуру метода и вызов метода?

Я получаю сообщение об ошибке «Программа…. Файл: minkernelcrtsucrtsrcappcrtconvertisctype.cpp … «Выражение c>= -1 amp;amp; c <= 255″», которое, я полагаю, связано с тем фактом, что эта строка неправильно передает данные обратно.

Комментарии:

1. imageBytes — это локальная переменная. Даже если это приведение было правильным (это не так), переменная все равно исчезает после завершения подпрограммы.

2. Есть ли у вас свобода изменять его внешний вид GetInfoAndPicture ? Я понимаю, что вы несете ответственность за его реализацию.

Ответ №1:

Укажите требования, чтобы избежать выделения большего объема памяти и копирования байтов. Вы не можете использовать вектор напрямую, потому что он является локальным для GetInfoAndPicture функции и будет уничтожен при выходе из этой функции.

Если я правильно понимаю API, то это то, что вам нужно сделать

 //*image = new char[imageBytes.size()];  //use this if caller calls delete[] to deallocate memory
*image = (char*)malloc(imageBytes.size());  //use this if caller calls free(image) to deallocate memory
std::copy(imageBytes.begin(), imageBytes.end(), *image);
*imageSize = imageBytes.size();
  

Возможно, в ваших функциях есть какой-то способ utility::conversions декодирования непосредственно в массив символов, а не в вектор, но об этом знаете только вы.

Комментарии:

1. Спасибо, Джон. Теперь я получаю следующие ошибки «Вызов std::copy’ с параметрами, которые могут быть небезопасными» и «= не удается преобразовать из unsighed char в char *» в строке, которая вызывает std::copy? У меня нет способа декодировать в массив символов напрямую, в соответствии с типом, который я использовал выше.

2. @pixel Извините за мою ошибку, std::copy(imageBytes.begin(), imageBytes.end(), *image); пропустил * раньше image . Вы также можете использовать memcpy для выполнения той же работы, если вы с этим более знакомы. Сообщение о небезопасных параметрах — это просто предупреждение. Компилятор MS очень чувствителен ко всему, что может вызвать переполнение буфера, приведенный выше код выделяет достаточно места.

3. еще раз спасибо. Это устранило 2-ю ошибку, но первая все еще присутствует, и это не предупреждение, а ошибка «Ошибка C4996 ‘std::copy::_Unchecked_iterators::_Deprecate’: Вызов ‘std::copy’ с параметрами, которые могут быть небезопасными — этот вызов зависит от вызывающего, чтобы проверить, что переданныйзначения верны. «. И нет, я не знаком с memcopy и C или C в целом. Очень ново для этих языков.

4. @pixel ХОРОШО, рад, что это работает. Поскольку вы новичок в C , я должен просто упомянуть, что код, который я дал, пропускает память. В какой-то момент вам нужны данные delete[] изображения.

5. @pixel кажется разумным, если вызывающий объект использует free , то malloc здесь необходимо использовать. Я только что изменил deallocate() delete[] в комментарии.

Ответ №2:

Проблема заключается в выделении (и освобождении) памяти для этого изображения; кто несет за это ответственность?

Вы не можете (не должны) выделять память в одном модуле и освобождать ее в другом.

Ваши два варианта:

  1. Выделите достаточно большой буфер на стороне вызывающей стороны и попросите DLL использовать его utility::conversions::from_base64() . Проблема здесь в том, что достаточно велико? Некоторые Win API предоставляют дополнительный метод для запроса требуемого размера. Не подходит для этого сценария, поскольку DLL должна либо получить это изображение во второй раз, либо удерживать его (неопределенно долго), пока вы не попросите об этом.
  2. Выделите необходимый буфер в DLL и верните на него указатель. Вам необходимо убедиться, что он не будет освобожден до тех пор, пока вызывающий не запросит его освободить (в отдельном API).