Литье 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__ для большей портативности. Некоторые компиляторы, как известно, предупреждают о прагмах, которые они не признают, если только такие прагмы #ifdefed out.