archives.c: In function ‘fd_writeback_wait’:
archives.c:121:21: warning: passing argument 1 of ‘aio_suspend’ from incompatible pointer type [-Wincompatible-pointer-types]
r = aio_suspend(&cb, 1, NULL);
^~~
In file included from ../lib/dpkg/fsys.h:28,
from ../lib/dpkg/triglib.h:28,
from archives.c:57:
/usr/include/aio.h:168:51: note: expected ‘const struct aiocb * const*’ but argument is of type ‘struct aiocb **’
extern int aio_suspend (const struct aiocb *const __list[], int __nent,
~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~
Пояснения:
Я думаю, что нет никакого способа избежать этого предупреждения, не написав опасное приведение типа для изменения квалификаторов const или подавляя всю категорию предупреждений.
Очевидно, C++ здесь лучше. Он также имеет const_cast
для более четкого приведения, что гарантирует, что вы Только изменяете квалификаторы const.
Другими словами, POSIX, определяющий aio_suspend() для использования const
, возможно, довольно опасен.
Я правильно это истолковал?
Если я ошибаюсь, то как мне избежать этого предупреждения, но при этом заставить компилятор проверить, что я привожу только квалификаторы const
, а не привожу к совершенно несовместимому типу?
Я подозреваю, что если бы и были методы, то они не были бы теми, которые я хотел бы использовать на практике, но мне любопытно.
Текущий код, над которым я работаю, явно не документирует требуемую версию компилятора.
Мне были бы интересны методы, которые работают в стандартных версиях C. Мне было бы интересно услышать о расширениях GCC. Также приветствуются комментарии о том, рекомендуется или не рекомендуется определять такие параметры функции.
Напоминаем читателям, что C и C++ разные, и нет 100% совместимые языки. Я признаю, что переход на C++, вероятно, мог бы стать решением, но я не думаю, что это решение было бы очень полезным для меня. Спасибо.
Вот способ вызвать функцию с соответствующей const
ness:
struct aiocb cb;
const struct aiocb * cblist[1] = { &cb };
aio_suspend(cblist, 1, NULL);
И альтернативно:
struct aiocb cb;
const struct aiocb * cbptr = &cb;
aio_suspend(&cbptr, 1, NULL);
Обратите внимание, что приведенный выше ответ был предложен, потому что вы использовали этот синтаксис:
r = aio_suspend(&cb, 1, NULL);
Передача адреса cb
чему-то, что ожидает указатель на указатель, означает, что cb
был указателем, поэтому этот вызов имеет смысл только для массива с одним элементом.
Предположим, ваше предупреждение появилось, потому что у вас действительно было это:
struct aiocb *cbv[256];
r = aio_suspend(cbv, 256, NULL);
Предупреждение легко убрать. Используйте (void *)
.
r = aio_suspend((void *)cbv, 256, NULL);
Однако было бы лучше определить вектор, который будет использовать указатели на const
в первую очередь.
const struct aiocb *cbv[256];
r = aio_suspend(cbv, 256, NULL);
Если каждый экземпляр обратного вызова действительно изменяем в действительности (например, был выделен malloc
), то просто отбросьте const перед изменением.
struct aiocb *cb = (struct aiocb *)cbv[i];
/* ... modify cb ... */
@sourcejedi: на самом деле вы не представили такой вариант использования. Тем не менее я расширил свой ответ.
Абсолютно согласен, и я извиняюсь :-). Придирка: и cb
, и &cb
работают, если cb
объявлен как struct aiocb *cb[1]
— массивы такие странные. Вы были бы правы, если бы догадались, что я не писал свой код так :-).
У них может быть один и тот же адрес, но разные типы. tio.run/…
FWIW, добавление нескольких квалификаторов const
в нужном месте теперь позволяет избежать как предупреждения компилятора, так и необходимости любых приведений типов для добавления/удаления констант. Кажется, что POSIX aio_suspend()
в конце концов вполне пригоден для использования :-). Спасибо.
Точка! А для сайта вызова это точное предупреждение о том, что было бы нормально. Но у меня также есть сайт вызова, где массив содержит до 256 записей, и он модифицируется и используется повторно. Даже если можно скопировать весь массив в константную локальную переменную и даже если оптимизатор знает, как исключить копию, я подозреваю, что это не будет очень идиоматичным кодом C.