我为字符串比较编写了这段简单的代码
#include<stdio.h>
void strCmp(char *,char *);
int main() {
char* str1 = "hello";
char* str2 = "hello";
strCmp(str1,str2);
return 0;
}
void strCmp(char *vp1,char *vp2) {
int r = strcmp(vp1,vp2);
printf("result %d",r);
}然后,为了检查如果我传递void*而不是char*会发生什么,我重写了如下代码:
#include<stdio.h>
void strCmp(void *,void *);
int main() {
char* str1 = "hello";
char* str2 = "hello";
strCmp(str1,str2);
return 0;
}
void strCmp(void *vp1,void *vp2) {
int r = strcmp(vp1,vp2);
printf("result %d",r);
}上面的代码被编译并按预期工作!如果我再疯狂一次
#include<stdio.h>
void strCmp(void **,void **);
int main() {
char** str1 = "helloxx";
char** str2 = "hellox";
strCmp(str1,str2);
return 0;
}
void strCmp(void **vp1,void **vp2) {
int r = strcmp(vp1,vp2);
printf("result %d",r);
}没有失败,结果也很好。我想知道strcmp的实现是什么,并在我的代码中将来自https://stackoverflow.com/a/10927187/2304258的代码粘贴为一个自定义函数,但是当您使用不强制转换的void*时,它失败了。
请您解释一下上述实现是如何工作的吗?
发布于 2015-07-23 08:59:44
你的问题有两点。
第一个原因是它的实际工作原理。第二个问题是,您的程序是否始终能够正常工作。
第一点的答案是,它可以工作,因为strcmp只需要两个指针作为参数。这些指针是char *类型的,它们应该包含指向以字符(字节)结尾的空序列的地址。不同的实现采用这样的两个指针,然后将它们转换为各种类型(第一个是void *,第二个是char ** ),然后将它们转换回char *,然后调用strcmp。它可以工作,因为在几乎所有实际的C实现中,将一种指针类型转换为另一种类型并不会改变指针的值。因此,不管是哪个指针,以及您转换和重铸指针的次数。请注意,在C++中情况不同,因为强制转换经常更改实际地址(指针的值)。
第二点是你的程序是否符合C标准。在这种情况下,第一个是正确的,因为C标准说,始终可以转换到void *的任何指针,并且当您将其转换回原始类型时,您将得到原始指针。但是,对于转换到其他类型并不是这样,因此不能保证在将char *转换为char **并返回到char *之后,您将得到原始指针。C语言不能保证你的上一个程序能工作。
更准确地说,以下是C99标准的两个相关引号:
6.3.2.3指针 1.)指向空的指针可以转换为指向任何不完整类型或对象类型的指针,也可以从指针转换为指向对象类型的指针。指向任何不完整或对象类型的指针可以再次转换为无效指针和返回指针;结果应与原始指针相比较。
..。
7.)指向对象或不完全类型的指针可以转换为指向不同对象或不完全类型的指针。如果结果指针不能正确地指向类型( aligned57),则行为未定义。否则,当再次转换回时,结果将与原始指针进行比较。当指向对象的指针转换为指向字符类型的指针时,结果指向对象的最低寻址字节。结果的连续增量,直到对象的大小,会产生指向对象剩余字节的指针。
发布于 2015-07-23 08:47:01
嗯,首先,你真的应该
#include <string.h>其次,强烈建议您使用strncmp()。最后,这正是C的工作方式(与C++不同)。它将执行从void*到任何其他指针的隐式强制转换(这就是为什么malloc()只是工作的原因)。另见How to interpret section 6.3.2.3 part 7 of the C11 standard?。
至于为什么libc的代码不适用于您,我不知道。它确实对我有效(在我修复了缺失类型声明之后)。
发布于 2015-07-23 08:51:25
它之所以有效,是因为C几乎总是假设程序员知道它做了什么。
即使str1和str2声明为char**,它们实际上包含指向char的指针。
C自动将任何类型的指针转换为指向void的指针。
最后,将char *传递给strcmp,它可以完成它的工作。
但是,当我编译它时,我得到了警告(即使在添加了#include <string.h>,以便对strcmp有一个正确的声明之后):
foo.c(7) : warning C4047: 'initialisation' : 'char **' diffère de 'char [8]' dans les niveaux d'indirection
foo.c(8) : warning C4047: 'initialisation' : 'char **' diffère de 'char [7]' dans les niveaux d'indirection
foo.c(13) : warning C4047: 'fonction' : 'const char *' diffère de 'void **' dans les niveaux d'indirection
foo.c(13) : warning C4024: 'strcmp' : types différents pour le paramètre formel et réel 1
foo.c(13) : warning C4047: 'fonction' : 'const char *' diffère de 'void **' dans les niveaux d'indirection
foo.c(13) : warning C4024: 'strcmp' : types différents pour le paramètre formel et réel 2在英语中,它或多或少应该是:
foo.c(7) : warning C4047: 'init' : 'char **' and 'char [8]' have different indexation level
foo.c(8) : warning C4047: 'initialisation' : 'char **' and 'char [7]' have different indexation level
foo.c(13) : warning C4047: 'function' : 'const char *' and 'void **' have different indexation level
foo.c(13) : warning C4024: 'strcmp' : different types for formal and actual parameter 1
foo.c(13) : warning C4047: 'function' : 'const char *' and 'void **' dhave different indexation level
foo.c(13) : warning C4024: 'strcmp' : different types for formal and actual parameter 2这些警告不应被忽略,因为它们会在代码中显示真正的问题。
https://stackoverflow.com/questions/31582061
复制相似问题