在c中将Const转换为非Const

时间:2017-06-04 16:06:03

标签: c casting

我正在开展一个学校项目,我需要重现许多C库函数。我只是在努力解决它的一个特定方面。

如果查看memchr的手册页,您会看到它需要const void *作为输入并返回普通void *。我假设函数中的某个位置从const转换为非const以获取返回变量。

然而,当我这样做(clang -Weverything +Werror)时,它不会编译。它在没有-Weverything标签的情况下工作,但无论如何我更愿意使用它。

有没有"正确"这样做的方法?

3 个答案:

答案 0 :(得分:3)

正如您所正确指出的,某些C库函数必须转换其const指针参数以删除返回值的const限定符:memchrstrchrstrstr等其他标准函数将指向解析后的字符串末尾的指针存储到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函数在指向的对象的初始n个字符(每个解释为c)中找到第一次出现unsigned char(转换为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;
}

答案 1 :(得分:1)

这个黑客会做到这一点。实际上,sizeof(void *)在每个但最晦涩的平台上等于sizeof(size_t)。不过,我建议不要使用它。您应该删除-Weverything。标准C函数可以追溯到70&#39;并且初始C编译器比今天的Clang或GCC严格得多,并且启用了所有警告。事实上你会找到一些不安全的东西&#34;其中一些是不可避免的。

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;
}

答案 2 :(得分:0)

问题是由特定位置的-Wcast-qual选项触发的不需要的GCC样式(包括Clang)诊断(-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__以提高可移植性。众所周知,一些编译器会警告他们不会认识到的pragma,除非这些编译指示被#ifdef删除。