C 试图理解指针加减法,但是
我不知道如何描述我的问题,但问题是:在阅读K&R的书时,我试图更好地理解指针。我使用了他们版本的strlen(),它使用指针,效果很好。为了进一步试验指针算法,我编写了一个非常简单的代码:C 试图理解指针加减法,但是,c,pointers,long-integer,C,Pointers,Long Integer,我不知道如何描述我的问题,但问题是:在阅读K&R的书时,我试图更好地理解指针。我使用了他们版本的strlen(),它使用指针,效果很好。为了进一步试验指针算法,我编写了一个非常简单的代码: #include <stdio.h> int main(void) { char s[10]; char *sp; sp = s; printf("%d\n", (sp+7) - s); return 0; } 我知道错误是什么,但我不知道为什么会发
#include <stdio.h>
int main(void)
{
char s[10];
char *sp;
sp = s;
printf("%d\n", (sp+7) - s);
return 0;
}
我知道错误是什么,但我不知道为什么会发生这种情况。该表达式是如何变成长型的?如果警告出现在
返回中,则在:
int istrlen(char *s)
{
...
return p - s;
}
那么你的编译器是有帮助的。。。在这种情况下,如果您请求-Wconversion
,gcc将生成警告,因为
定义了求和(C99 6.5.6),其中两个都是指针(指向同一数组对象的元素,或指向同一数组对象最后一个元素的过去一个),以给出类型为ptrdiff\u t
的结果,这是一个有符号整数。现在,在典型的64位处理器上,ptrdiff\u t
将是一个64位有符号整数,int
是一个32位有符号整数。因此,编译器可能会警告您,从64位到32位有符号整数的转换可能会出现溢出
你可以写:
return (int)(p - s) ;
要对此负责,编译器将耸耸肩,继续它的生命
[我有点惊讶的是,这个警告没有直接的-Wall
…所以这可能不是问题所指的警告。]
我的第二版K&R基本上是C89,还描述了ptrdiff\u t
及其palsize\u t
。我怀疑你所看到的代码片段来自一个更友善、更温和的时代,int
和ptrdiff\u t
是可互换的(32位整数)——或者编译器不太热衷于暗示程序员可能不知道他们在做什么。(请注意,在1989年,长度超过2147483647个字符的字符串极不可能出现!)
编译器可能有帮助的另一个地方是:
printf("%d\n", (sp+7) - s);
其中,减法的结果也是ptrdiff\u t
,但是%d
需要int
。这是一个更严重的问题,因为%d
只知道如何吃int
,吃int
可能会出错,特别是在后面有更多参数的情况下。减去两个指针会产生类型ptrdiff\u t
的结果,这是一个typedef(别名)对于某些实现定义的有符号整数类型
你有:
printf("%d\n", (sp+7) - s);
其中减法运算的操作数都是char*
类型的指针(s
是一个数组,它衰减为指向其第一个元素的指针)。“%d”
格式需要类型为int
的参数ptrdiff_t
显然是系统上的long
类型定义
要解决此问题,可以强制转换结果(可能是long
,但int
应该可以):
或者为ptrdiff\u t
使用正确的格式字符串:
printf("%td\n", (sp+7) - s);
就我个人而言,我可能会使用演员阵容;我不记得t
是ptrdiff\u t
的长度修饰符,直到我在标准中查找了它。(而且C99之前的实现可能不支持“%td”
)
传递的printf
参数不是格式字符串指定的正确类型(升级后),会导致未定义的行为。至于它为什么会工作,可能int
和long
在实现中具有相同的大小和表示形式,或者如果long
比int
更宽,可能long
参数的传递方式使得printf
尝试获取int
值(可能是堆栈外)它碰巧得到了long
参数的低位sizeof(int)
字节。这就是未定义行为的本质;可能发生的最糟糕的事情是它似乎工作正常。(这很糟糕,因为代码可能会在以后意外失败。)不要使用屏幕截图;将文本复制并粘贴到程序中。问题中的代码不会产生警告;屏幕截图中的代码会产生警告。向我们展示产生警告的代码以及问题中的警告本身。指针是长的
类型(例如32位)。但您告诉C将其打印为int(%d
),这是一种16位数据类型。0x12340001
和0x98760001
理论上都会打印出0x0001
,并且看起来完全相同,即使它们的值完全不同。@MarcB:不,指针不是“长的
类型”.指针是指针。减去两个指针的结果是类型ptrdiff\u t
,这是在
中定义的类型定义,对应于一些实现定义的带符号整数类型。int
至少是16个but,但通常更宽。但是,由于产生错误的代码不在问题中,我建议我们选择回答时d关闭。屏幕截图中显示的警告出现在一段代码上,而该代码没有出现在您的问题中!!!抱歉,各位已经修复了它。该语句不会产生报告的警告,添加强制转换也没有帮助。链接的屏幕截图显示了实际代码及其产生的警告。问题中当前的代码是基本上不相关。这个问题需要更新。(最好更改istrlen
,使其返回size\u t
,而不是int
)@KiethThompson…在我的gcc上,-Wconversion
生成警告:“从'long int'转换为'int'可能会改变其值”。然而,我承认,我有点惊讶于-Wall
和-Wextra
是不够的!我宁愿假设是返回s-p;
生成了警告。抱歉。在更成熟的思考中,并提供了进一步的信息
printf("%ld\n", (long)((sp+7) - s));
printf("%td\n", (sp+7) - s);