Литье Const в non Const в c
Я работаю над школьным проектом, в котором мне нужно воспроизвести многие функции библиотеки C. Я просто борюсь с одним специфическим аспектом.
если вы посмотрите на man-странице memchr
вы увидите, что она занимает const void *
в качестве ввода и возвращает plain void *
. Я бы предположил, что где-то в функции они бросают из const
не const
для возвращаемой переменной.
однако, когда я делаю это (clang -Weverything +Werror
) он не будет компилироваться. Он работает без the -Weverything
tag, но я бы предпочел использовать его, если это возможно.
есть ли "правильный" способ сделать это?
3 ответов
этот хак сделает это. На практике sizeof(void *)
равна sizeof(size_t)
на всех, кроме самых неясных платформ. Тем не менее, я бы не советовал использовать это. Вы должны упасть . Стандартные функции C датируются 70', а начальные компиляторы C были намного менее строгими, чем сегодняшние Clang или GCC со всеми включенными предупреждениями. Тот факт, что вы найдете что-то "небезопасное" в некоторых из них неизбежна.
void * memchr_(const void * ptr_, int c, size_t num);
int main(void)
{
unsigned char ary[] = { 1, 6, 2, 45, 23, 75, 23, 43, 23 },
* ptr = NULL;
ptr = memchr_(ary, 23, sizeof(ary) / sizeof(ary[0]));
printf("ary = %p, ptr = %p, *ptr = %u\n", (void *)ary, (void *)ptr, *ptr);
return 0;
}
void * memchr_(const void * ptr_, int c, size_t num)
{
size_t i;
const unsigned char * ptr = ptr_;
for(i = 0; i < num; i++) {
if(ptr[i] == (unsigned char)c) {
/* Casting to size_t first so that the compiler doesn't complain */
return (unsigned char *)(size_t)ptr + i;
}
}
return NULL;
}
как вы правильно заметили, некоторые функции библиотеки C должны привести свой аргумент указателя const, чтобы удалить const
квалификатор возвращаемого значения:memchr
, strchr
, strstr
etc. Другие стандартные функции хранят указатель на конец анализируемой строки в char **
, хотя он указывает на массив, к которому они были переданы const char *
: strtol
, strod`...
если ваш компилятор анал об этом и выдает предупреждения, попробуйте кастинг uintptr_t
перед заливкой в unsigned char *
. Вы также можете использовать union
С обоими типами указателей.
стандарт C указывает memcpy
таким образом:
7.24.5.1 в
memchr
функциисправка
#include <string.h> void *memchr(const void *s, int c, size_t n);
описание
на
memchr
функция находит первое вхождениеc
(преобразован вunsigned char
) в начальных N символах (каждый интерпретируется какunsigned char
) об объекте, на который указываетs
. Реализация должна вести себя так, как если бы она считывает символы последовательно и останавливается, как только соответствующий символ найден.возвращает
на
memchr
функция возвращает указатель на расположенный символ или нулевой указатель, если символ не встречается в объекте.
если вы не можете использовать другие типы, вы можете уйти с литой как size_t
для подавления компилятор внимание, вот возможная реализация:
void *my_memchr(const void *ptr, int c, size_t num) {
const unsigned char *cptr = ptr;
while (num-- > 0) {
if (*cptr++ == (unsigned char)c) {
/* const pointer is cast first as size_t to avoid a compiler warning.
* a more appropriate type for this intermediary cast would be uintptr_t,
* but this type is not allowed here.
*/
return (void *)(size_t)(cptr - 1);
}
}
return NULL;
}
проблема заключается в нежелательной GCC-стиле (Clang включены) диагностики, вызванной -Wcast-qual
опция в определенном месте (-Weverything
включает в себя -Wcast-qual
). Решение состоит в том, чтобы отключить просто -Wcast-qual
на просто это место.
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
void* non_const_ptr = (void*)const_ptr;
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
приведение к типу без указателя и обратно к типу указателя будет препятствовать всем видам полезной диагностики оптом и, таким образом, победить цель -Weverything
.
#ifdef __GNUC__
для большей портативности. Некоторые компиляторы, как известно, предупреждают о прагмах, которые они не признают, если только такие прагмы #ifdef
ed out.