我正在开展一个学校项目,我需要重现许多C库函数。我只是在努力解决它的一个特定方面。
如果查看memchr
的手册页,您会看到它需要const void *
作为输入并返回普通void *
。我假设函数中的某个位置从const
转换为非const
以获取返回变量。
然而,当我这样做(clang -Weverything +Werror
)时,它不会编译。它在没有-Weverything
标签的情况下工作,但无论如何我更愿意使用它。
有没有"正确"这样做的方法?
答案 0 :(得分:3)
正如您所正确指出的,某些C库函数必须转换其const指针参数以删除返回值的const
限定符:memchr
,strchr
,strstr
等其他标准函数将指向解析后的字符串末尾的指针存储到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
删除。