我不知道如何描述我的问题,但事情就是这样:在阅读K& R的书时,我试图更好地理解指针。我使用了他们使用指针的strlen()版本,并且运行正常。为了进一步尝试指针运算,我写了一个非常简单的代码:
#include <stdio.h>
int main(void)
{
char s[10];
char *sp;
sp = s;
printf("%d\n", (sp+7) - s);
return 0;
}
它运行正常,但我不明白发生此警告的原因:
hello3.c:10:17: warning: format specifies type 'int' but the argument has type
'long' [-Wformat]
printf("%d\n", (sp+7) - s);
~~ ^~~~~~~~~~
%ld
我明白错误是什么,但我不知道为什么会这样。那个表达式怎么变成了长型?
答案 0 :(得分:0)
如果警告在return
上,请输入:
int istrlen(char *s)
{
...
return p - s;
}
然后你的编译器很有用......在这种情况下,如果你要求-Wconversion
,gcc会生成一个警告,因为......
...定义了总和p - s
(C99 6.5.6),其中两者都是指针(对同一个数组对象的元素,或者是同一个数组对象的最后一个元素之后的一个),到给出ptrdiff_t
类型的结果 - 这是一个有符号整数。现在,在典型的64位处理器上,ptrdiff_t
将是一个64位有符号整数,而int
是一个32位有符号整数。因此,您的编译器可能会警告您从64位到32位有符号整数的转换,可能会有溢出。
你可以写:
return (int)(p - s) ;
对此负责,编译器会耸耸肩,继续它的生命。
[我有点惊讶的是,警告没有直截了当-Wall
......所以这可能不是问题所指的警告。]
我的第二版K&amp; R基本上是C89,还描述了ptrdiff_t
及其朋友size_t
。我怀疑你正在查看的代码片段来自一个更温和,更温和的年龄int
和ptrdiff_t
可以互换(32位整数) - 或者编译器不太热衷于建议程序员可能不知道他们在做什么。 (请注意,在1989年,一个超过2,147,483,647个字符的字符串非常不可能!)
编译器可能有用的另一个地方是:
printf("%d\n", (sp+7) - s);
同样,减法的结果为ptrdiff_t
,但%d
需要int
。这是一个更严重的问题,因为%d
只知道如何吃int
,并且可能会错误地吃int
,特别是在跟随它的地方有更多参数的情况下。
答案 1 :(得分:0)
减去两个指针会产生类型ptrdiff_t
的结果,这是某个实现定义的有符号整数类型的typedef(别名)。
你有:
printf("%d\n", (sp+7) - s);
其中减法的操作数都是char*
类型的指针(s
是一个衰减到指向其第一个元素的指针的数组)。 "%d"
格式需要int
类型的参数。 ptrdiff_t
显然是您系统上long
的typedef。
要解决此问题,请将结果(可能转到long
,但int
应该有效):
printf("%ld\n", (long)((sp+7) - s));
或使用ptrdiff_t
的正确格式字符串:
printf("%td\n", (sp+7) - s);
就个人而言,我可能会使用演员;我不记得t
是ptrdiff_t
的长度修饰符,直到我在标准中查找它。 (并且C99之前的实现可能不支持"%td"
。)
传递printf
格式字符串指定的不正确类型(提升后)的参数会导致未定义的行为。至于为什么它恰好起作用,或许int
和long
碰巧在您的实现中具有相同的大小和表示,或者long
是否宽于int
或许{{以这样的方式传递参数:当long
尝试获取printf
值(可能在堆栈外)时,它恰好获得{的低位int
字节{1}}论点。这是未定义行为的本质;可能发生的最差事情似乎是正常工作。 (这很糟糕,因为代码可能会在以后无法预测地失败。)