printf char *指向long和float的指针

时间:2013-04-22 14:37:31

标签: c printf long-integer

我正在从“理解C中的指针”一书中做一些练习。这本书为您提供了一段代码,并询问您输出的内容。

其中一项如下:

#include <stdio.h>

int main(int argc, char* argv[])
{
    char c, *cc;
    int i;
    long l;
    float f;

    c = 'Z';
    i = 15;
    l = 77777;
    f = 3.14;
    cc = &c;
    printf("c=%c cc=%u\n", *cc, cc);
    cc = &i;
    printf("i=%d cc=%u\n",*cc,cc);
    cc=&l;
    printf("l=%ld cc=%u\n",*cc,cc);
    cc=&f;
    printf("f=%f cc=%u\n",*cc,cc);
    return 0;
}

,输出为:

c=Z cc=1946293623
i=15 cc=1946293616
l=4294967249 cc=1946293608
f=0.000000 cc=4294967235

我不明白为什么 lf不会打印为777773.14

我检查了The C编程语言,看看printf的控件字符是否正确,是否正确。

5 个答案:

答案 0 :(得分:3)

正如Bryan的回答所说,传递给printf的参数类型需要匹配格式字符串指定的类型。

打印指针值的格式为"%p" - 它需要void*参数;应该将另一种类型的指针显式转换为void*

由于类型不匹配,您的程序具有未定义的行为。它也有约束违规,因为它试图在没有强制转换的情况下分配不兼容的指针类型; cc = &i;是非法的(但编译器只能在选择时对其进行警告)。你 应该从你的编译器得到几个警告。

希望该计划的目的是展示要做的事情。我们只考虑return语句之前的最后两行:

cc=&f;
printf("f=%f cc=%u\n",*cc,cc);

cc = &f;违反约束并需要诊断(恕我直言,好的编译器应该给你一个致命错误并拒绝该程序)。 &f的类型为float*cc的类型为char*;这些类型不是赋值兼容的。

接受该语句的大多数编译器都假设它暗示了隐式转换,使其等同于合法但非常棘手:

cc = (char*)&f;

这会导致cc指向float对象f的第一个字节。

printf("f=%f cc=%u\n",*cc,cc);

此声明打印f的值,但不是;它打印char指向的cc对象的值,恰好是f的第一个字节。它为%f对象使用char格式,该对象具有未定义的行为。结果是垃圾。

我打算写一个该程序的“更正”版本,但它有很多问题,我无法弄清楚它的目的是什么。

  

我检查了The C编程语言,看看printf的控制字符是否正确,它们是否正确。

不,他们不是。 "%f"对于打印floatdouble参数(float在此上下文中被提升为double)是正确的,但您传递的是{{1}参数。

这是正确的:

char

但它没有做同样的事情;它将printf("*cc = %d, cc = %p\n", *cc, (void*)cc); 指向的字符打印为cc(您可以使用int将其打印为字符,但它可能是不可打印的),然后打印{的值{ {1}}作为指针。

看看这本书关于这个节目的内容会很有趣。

答案 1 :(得分:2)

printf的格式说明符(更糟糕的是scanf)必须与作为参数传递的类型相匹配。如果您使用gcc,请使用-Wall选项,它也会发出警告。您的代码应如下所示:

printf("c=%c cc=%u\n", *cc, (unsigned int)cc);
cc = &i;

i的地址转换为char*解释不再有意义,也不适用于下面的其他人。通过分配指针,您可以对相同的位表示执行错误的解释。

答案 2 :(得分:1)

printf("l=%ld cc=%u\n",*(long*)cc,cc);
printf("f=%f cc=%u\n",*(float*)cc,cc);

这可行,但

printf("l=%ld cc=%u\n",*cc,cc);
printf("f=%f cc=%u\n",*cc,cc);

这并不是出于以下原因而预期。

每个指针都是4个字节(取决于操作系统,而不是它指向的位置)。 所以即使是float的地址也可以存储到char *中。 当我们做指针算术时或者当我们读取指针*cc的值时,它会根据指针的类型读取字符的数量......

假设一个字符是2个字节,那么*cc将只读取2个字节,地址在cc中,其中浮点数或长数字存储在4个字节(或更多)中。 所以它会显示无效数据。

当我们对它进行类型转换*(long*)cc时,它会被指定为具有显式类型转换的长指针。

答案 3 :(得分:1)

  

你的程序有很多错误!

首先,不要使用%u格式说明符作为指针。unsigned integerspointers基本上不必具有相同的大小。始终使用%p pointers。例如

printf("c=%c cc=%p\n", *cc, cc);

第二个最重要的事情 - 从不使用YK的那本书“理解C中的指针”(由于显而易见的原因,我无法完全命名作者)。他的另一本书是臭名昭着的SO的“无效主要”一书。

第三,回到你的程序,我很惊讶你没有得到任何警告,而你将整数和浮点变量的地址分配给一个字符指针没有强制转换。。这是绑定的产生错误,因为您的程序将无法知道从指向的位置解释多少字节。 intfloatchar的大小各不相同。你可能想知道为什么你没有得到int的错误呢?对?这是因为计算机的小端架构,首先存储最不重要的字节。

所以这是你的更正:

cc =(char*) &i;
printf("i=%d cc=%p\n",*(int*)cc,cc);
cc=(char*)&l;
printf("l=%ld cc=%p\n",*(long*)cc,cc);
cc=(char*)&f;
printf("f=%f cc=%p\n",*(float*)cc,cc);

答案 4 :(得分:0)

试试这个

printf("l=%ld cc=%u\n",*(long*)cc,cc);
printf("f=%f cc=%u\n",*(float*)cc,cc);