我正在进行一个学校项目,需要重现许多C库函数。但是我在其中遇到了一些困难。
如果你查看memchr
的man页面,你会看到它将const void *
作为输入并返回一个普通的void *
。我会假设在函数的某个地方,他们将返回变量从const
转换为非const
。
然而,当我这样做时(clang -Weverything +Werror
),它无法编译。没有-Weverything
标签时可以工作,但是如果可能的话,我更喜欢使用它。
有任何“正确”的方法吗?
-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,除非这样的#pragma被#ifdef
掉。
如果您无法使用其他类型,则可以使用7.24.5.1 The
memchr
functionSynopsis
#include <string.h> void *memchr(const void *s, int c, size_t n);
Description
The
memchr
function locates the first occurrence ofc
(converted to anunsigned char
) in the initialn
characters (each interpreted asunsigned char
) of the object pointed to bys
. The implementation shall behave as if it reads the characters sequentially and stops as soon as a matching character is found.Returns
The
memchr
function returns a pointer to the located character, or a null pointer if the character does not occur in the object.
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;
}
更新:
使用return cptr - 1;
将会发出警告,因为隐式转换为void *
时,const
限定符被移除。
显式地将返回值强制转换为return (void *)(cptr - 1);
就足够了,但是一些编译器仍然会发出警告,以帮助程序员避免错误。使用额外的中间转换return (void *)(uintptr_t)(cptr - 1);
或return (void *)(size_t)(cptr - 1);
并不会改变转换的语义,因为uintptr_t
和size_t
应该足够大,可以在指针和整数类型之间进行往返转换,并且通常可以停止编译器发出的警告。
(size_t)
,它在大多数当前架构上与指针大小相同,但这并不是严格正确的做法,而定义一个union
会更简单,使用标准类型uintptr_t
则是正确的。 - chqrlie#ifdef
测试来包围它,这使得整个过程相当丑陋。 - chqrliesizeof(void *)
等于sizeof(size_t)
。然而,我建议不要使用它。你应该放弃-Weverything
。标准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;
}
CHAR_MAX
字节值存在问题。memchr
的正确语义要求您编写if (ptr[i] == (unsigned char)c)
。 - chqrlieuintptr_t
而不是size_t
。 - chqrlie
memchr
这样的情况下,这可能是必要的。 - Some programmer dudeconst void *memchr(const void *, int, size_t)
和void *memchr(void *, int, size_t)
,这是为了避免该函数破坏const
。然而,C 不允许函数重载。 - ephemient-Weverything
是过度的。-Wall -Wextra -pedantic
通常足够开始使用。 使用-Weverything
你会得到很多错误的警告,这些警告可能与当前问题无关或不必要,或者完全是错误的。 - Some programmer dude