Семантический конфликт, передающий указатель на константный указатель на байтовый массив

Я хочу вызвать эту функцию из библиотеки OpenSSL, определенной с помощью прототипа ниже:

X509 *d2i_X509(X509 **px, const unsigned char **in, int len);

Второй параметр in определяется как const unsigned char ** так как:

  • d2i_X509 не будет изменять данные в буфере, на который указывает *in
  • *in будет увеличен на количество данных, проанализированных из буфера.

Теперь этот прототип представляет собой проблему, потому что, насколько я вижу, функцию нельзя вызывать следующим образом, который, насколько я понимаю, является нормальным способом вызова API (код управления ошибками удален, чтобы упростить задачу):

unsigned char buffer[2048];
unsigned char * end = buffer;
unsigned char * p = buffer;

end += read(fd, p, 2048);
certlen1 = parseint(&p);
X509 * cert1 = d2i_x509(NULL, &p, certlen1);
certlen2 = parseint(&p);
X509 * cert2 = d2i_x509(NULL, &p, certlen2);

Если я пытаюсь скомпилировать приведенный выше код, он говорит:

error: invalid conversion from 'unsigned char**' to 'const unsigned char**'

Я понимаю обоснование сообщения (объяснил Вот например), но в данном конкретном случае это обоснование не применяется, так как функция состояния в своей документации, она будет только увеличивать значение *inНикогда не назначайте на него не связанный указатель.

Я не могу изменить тип р на const unsigned char * Поскольку приведенный выше код на самом деле упрощен, указатель скрыт за каким-то абстрактным объектом ввода-вывода, выполняющим как чтение, так и запись. Хорошим моментом с предыдущим объектом ввода-вывода является то, что он поддерживает симметричное чтение и запись кода вместе, можно использовать два отдельных указателя для чтения и записи в моем объекте ввода-вывода, но общее преимущество от этого действительно мало (если не отрицательно) и добавить много синтаксического шума. Подобные глубокие внутренние изменения в объекте ввода-вывода, вызванные каким-либо внешним несвязанным вызовом API, выглядят действительно растянутыми.

Решением может быть выполнение приведения или даже вообще не использовать возвращаемое значение указателя (так как у меня есть параметр размера), но это тоже не так. Похоже, что прототип d2i_X509 не содержит достаточно информации, или что правило проверки констант компилятора в этом случае слишком строгое.

Как вызвать такой API из C ++? Пока я просто буду использовать актерский состав, поскольку я чувствую, что это меньшее зло, но есть ли лучший способ?

2

Решение

Во-первых, += в этом коде нет особого смысла:

p += read(fd, p, 2048);

Вы модифицируете p В точку только что прошел данные, которые вы только что прочитали, так d2i_x509 буду читать барахло.

Я бы сделал это так:

unsigned char buffer[2048];
int n = read(fd, buffer, 2048);
if (n < 0) ..error..;
const unsigned char * p = buffer;
X509 * cert1 = d2i_x509(NULL, &p, certlen1);
X509 * cert2 = d2i_x509(NULL, &p, certlen2);
int used = p - buffer;  // # of bytes actually parsed by the two calls

Любые будущие изменения могут быть сделаны в buffer непосредственно.

Редактировать:

Хорошо, тогда замените это:

X509 * cert1 = d2i_x509(NULL, &p, certlen1);

с этим:

{
const unsigned char *q = p;
X509 * cert1 = d2i_x509(NULL, &q, certlen1);
p += q - p;
}
1

Другие решения

Других решений пока нет …