【问题标题】:Using printf with a pointer to float gives an error使用带有指向浮点数的指针的 printf 会产生错误
【发布时间】:2014-03-02 12:48:44
【问题描述】:

当我尝试编译这段代码时:

void main()
{
float x;
    x=6.5;
    printf("Value of x is %f, address of x %ld\n", x, &x);
}

它给了我这个错误:

pruebso.c:在函数“main”中:

pruebaso.c:5:9:警告:内置函数“printf”的隐式声明不兼容[默认启用]

printf("x的值为%f,x的地址%ld\n", x, &x);

^

pruebaso.c:5:9:警告:格式“%ld”需要“long int”类型的参数,但参数 3 的类型为“float *”[-Wformat=]

我在另一个论坛中看到解决方案是先强制转换为 void 指针: http://www.linuxquestions.org/questions/programming-9/beginning-c-programming-how-to-print-memory-locations-printf-conversion-number-927305/

但是做出这样的改变,

printf("Value of x is %f, address of x %ld\n", (double)x, (void *)&x);

现在给我一个警告:

pruebso.c:在函数“main”中:

pruebaso.c:5:9:警告:内置函数“printf”的隐式声明不兼容[默认启用]

printf("x的值为%f,x的地址%ld\n", (double)x, (void *)&x);

^

pruebaso.c:5:9:警告:格式“%ld”需要“long int”类型的参数,但参数 3 的类型为“void *”[-Wformat=]

谁能解释我如何在没有警告的情况下解决它?

谢谢

【问题讨论】:

  • 使用%p 打印指针。
  • 这是int main(void),而不是void main()。 (一些编译器碰巧接受void main(),但没有充分的理由使用它。)我很好奇:你从哪里知道void main() 是正确的?

标签: c pointers floating-point printf


【解决方案1】:

您需要包含<stdio.h> 来禁止第一个警告,并使用转换为void * 并使用%p 来禁止第二个警告。

在 C90 中,使用 printf() 而不使用 <stdio.h> 会调用未定义的行为,因为隐式声明与实际声明不匹配,因为 printf() 是可变参数。 (相比之下,使用fputs() 就可以了。)在C99 中,不允许使用隐式声明,但GCC 允许您编译此类代码。

#include <stdio.h>
int main(void)
{
    float x = 6.5;
    printf("Value of x is %f, address of x %p\n", x, (void *) &x);
}

%p 格式说明符用于打印指针。从技术上讲,它必须与char *void * 指针一起使用。在现代系统上,这不会影响结果;但是将其他指针类型传递给%p 在技术上会调用未定义的行为(这很糟糕)。

您代码中的%ld 格式是错误的,尽管它适用于大多数系统。首先,它需要一个long 参数,该参数需要强制转换(即使强制转换只会在少数系统上产生影响)。其次,即使您添加演员表,也不能保证指针中的所有信息都保留(它可能会切断位或做其他事情)。实际上,64 位 Windows 系统是唯一可以转换为 long 位的系统,并且转换在其他任何地方都可以正常工作。

所以使用%p 并转换为void *

【讨论】:

  • 除了 Windows 64 位之外,还有其他系统 %ld 指针说明符可以工作
  • @chux:你能说出一个吗?我敢打赌它们是相当不寻常的。
  • Microchip 在 2013 年制造了超过 十亿 个处理器。C 语言在这里非常流行,其中许多处理器使用 16 位指针和 32 位 long。十亿足以让它们变得正常吗?
  • 但这仍然有效。 void *x; printf("x = %ld\n", (long) x);
  • @DietrichEpp:我想你的意思是(long) &amp;x。是的,它会起作用,但是将指针转换为整数类型的结果是实现定义的——并且不能保证将指针转换为long 不会丢失信息。 "%p" 专门用于打印指针值(以实现定义的方式),使用其他方法没有多大意义。
【解决方案2】:
void main()
{
    float x;
    x=6.5;
    printf("Value of x is %f, address of x %ld\n", x, &x);
}

直接的问题是您缺少所需的#include &lt;stdio.h&gt;,但这不是您的代码的唯一问题。其中一些错误是您可能可以逃脱的(编译器可能不会抱怨,并且可能会生成符合您期望的代码),但没有理由不正确地做。

#include <stdio.h>
int main(void)
{
    float x;
    x = 6.5;
    printf("Value of x is %f, address of x %p\n", x, (void*)&x);
}

解释我所做的更改:

  • 任何调用printf 的程序都需要#include &lt;stdio.h&gt;。更准确地说,printf 的声明是必需的,&lt;stdio.h&gt; 提供了它。 (原则上您可以编写自己的声明,但没有充分的理由这样做。)
  • main 的正确定义是int main(void)void main() 可能会被一些编译器接受,但它主要用作检测坏书的一种方法。如果您使用的一本书告诉您使用void main(),则其作者不太了解该语言,并且可能给您提供了其他错误信息。找一本更好的书。 (警告:void main(),或者更可能的是 void main(void) 实际上可能是某些嵌入式系统的首选实现定义形式。但您可能没有使用这样的系统。)
  • "%ld" 格式需要long int 类型的参数。打印指针值的唯一正确格式是"%p"。由于"%p" 需要void* 类型的参数,因此您应该将指针值显式转换为void*。省略强制转换可能会“起作用”,但 float*void* 是不同的类型,不能保证具有相同的表示形式或以相同的方式传递给函数。

【讨论】:

  • @Stella:谢谢你的链接。正如我所说,作者对 C 有一些错误的想法。我还没有阅读全文,但 void main() 足以建议避免使用它。它指的是 Kernighan & Ritchie 的 The C Programming Language;你不会在那本书的任何地方找到void main。另见comp.lang.c FAQ,问题 11.12a 到 11.15。 (这可能是唯一严重的错误,但我不会打赌。)
  • @KeithThompson:虽然我们在这里,你能推荐一个好的 C 教程吗?
  • @Grodriguez:Kernighan & Ritchie,“The C Programming Language”,第 2 版,是经典之作——尽管它假定有一些编程经验。 comp.lang.c FAQ 的第 18 节有一些很好的链接。
  • 我专门寻找教程(我正在为实习生编制有用资源列表),所以 K&R 并不是我真正想要的。但是 comp.lang.c FAQ 的第 18 节绝对有帮助,谢谢!
【解决方案3】:

如果在定义函数之前使用它们,C会隐式声明函数,这会导致错误“内置函数‘printf’的隐式声明不兼容”。 要解决此问题,请在文件顶部添加 #include &lt;stdio.h&gt;(这会复制包含 printf 声明的头文件。

第二个问题是你应该使用%p 来打印指针。

生成的代码是

#include <stdio.h>
int main(void)
{
  float x;
  x=6.5;
  printf("Value of x is %f, address of x %p\n", x, (void *) &x);
  return 0;
}

【讨论】:

  • C90 隐式声明的函数。 C99 放弃了该规则,并使得调用没有可见声明的函数成为违反约束的行为,需要进行诊断。 (gcc 的警告满足该要求。)
猜你喜欢
  • 1970-01-01
  • 2021-07-26
  • 2021-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-03
  • 2020-06-13
  • 1970-01-01
相关资源
最近更新 更多