从没有强制转换的整数生成指针... DS1307、RTC、BCD

makes pointer from integer without a cast... DS1307, RTC, BCD

我知道以前有人问过这个问题。 Google 和这个站点上都有,但是当人们解释时我听不懂。我已经花了太多时间试图理解,但我仍然不理解,所以请尝试理解一些我不理解的基本知识……我们开始吧。

在 Proteus 上用 C 编程时,我经常收到警告 and/or 错误(在本例中为警告):

makes pointer from integer without a cast

我不明白。就像我说的,我已经花了几个小时研究它,我知道它与类型、and/or 指针等有关。有人请像正常人一样给我解释一下。

此外,我经常得到这个。是否可以在不进行强制转换的情况下从其他类型的变量中获取此警告?一个人物?我现在如何解决这个问题,并在将来避免它?

这是上下文...

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "stdlib.h"
#include "USART.h"
#include "I2C.h"
#include "ds1307.h"

void Wait()
{
   uint8_t i;
   for(i=0;i<20;i++)
      _delay_loop_2(0);
}

uint8_t ss,mm,hh,dd,nn,yy,x;    // Appropriately labeled variables
uint16_t sec[3],min[3],hr[3],day[3],month[3],year[3],mode[2];
uint16_t secs,mins,hrs,days,months,years,modes;

int main(void)
{
   _delay_ms(50);
   USART_interrupt_init();          // 
   USART_send('\r');                // Send carriage return
   _delay_ms(100);              // Allows for the LCD module to initialize

   I2CInit();                   // Initialize i2c Bus
   DS1307Write(0x07,0x10);          // Blink output at 1Hz
   while(1)
      {
     int i=0;
     /* SECONDS */
     DS1307Read(0x00,&ss);      // Read seconds address
     /* MINUTES */
     DS1307Read(0x01,&mm);      // Read minutes address
     /* HOURS */
     DS1307Read(0x02,&hh);      // Read hours address
     /* DAY */
     DS1307Read(0x04,&dd);      // Read hours address
     /* MONTH */
     DS1307Read(0x05,&nn);      // Read hours address
     /* YEAR */
     DS1307Read(0x06,&yy);      // Read hours address
     for(i=0;i<5;i++)
     {Wait();i++;}

     sec[0]=(0b00001111 & ss);
     sec[1]=((0b01110000 & ss)>>4);
     sec[2]='[=11=]';
     itoa(sec[0],secs,10);

     USART_putstring(secs); // place string in buffer

和 2 个错误:

../main.c:59: warning: passing argument 2 of 'itoa' makes pointer from integer without a cast

../main.c:62: warning: passing argument 1 of 'USART_putstring' makes pointer from integer without a cast

您的编译器告诉您该函数需要一个指针,但您传递的是一个整数。所以它会自动将您的整数值视为地址并将其用作指针。

例如,itoa 需要一个指向其第二个参数的内存位置的指针 - 这是它存储根据您传递给它的整数构建的结果字符串的位置。但是您已经通过了 secs - uint16_t。编译器警告您,该整数中的任何值都将用作 itoa 放置其结果字符串的地址。

这种事情会在大多数目标上导致段错误,但我对 Proteus 不熟悉。

无论如何,作为示例,要修复 itoa 警告,请使用如下内容:

char secs[3];
...
itoa(sec[0], secs, 10);

希望对您有所帮助。

这意味着编译器隐式 为您转换它,但是,它会通过发出警告通知您它已转换,因此您知道。

这是一个使用数字的例子:

float f = 1.0;
int i = f;

根据平台、语言和编译器设置,可能有几种情况:

  • 编译器在没有警告的情况下将 float 隐式转换为 int(不好)
  • 同上但发出警告(更好)
  • 编译器设置更改为将警告视为错误(安全、安全关键等...)

警告是对可能存在的错误或错误的良好提示,通常明智的做法是修复它们而不是抑制或忽略它们。

在您的具体情况下,我一直在寻找 USART_pustring,我找到的第一个就是这个:

void USART_putstring(char* StringPtr)

无需进一步查看,将 int 传递给期望 char* 的函数(如果是这种情况),'might' 会产生意想不到的结果。

解决方案

阅读 USART_putstring 的文档并确保您 'transform' 您的输入数据为它接受的正确类型,警告将自行消失。

编辑:

+1 for Aenimated1

确保您也了解 'integer' 和 'pointer to integer' 之间的区别,他解释得很好 :)

整数用于计数。指针是变量所在位置的抽象指示。

为了让你的头脑清楚,最好不要混淆两者,即使你在一个指针的具体实现与整数的实现相同的系统上也是如此。

将整数转换为指针或相反是错误的,除非你写一个 cast 来表示 "I know what I'm doing here"。

不幸的是,一些编译器会吐出 "warning" 然后生成一个伪造的二进制文件。如果可能,看看您是否可以使用编译器开关,让编译器在这种情况下说 "error"。

如果您看到此错误,通常意味着您在编译器希望您提供指针的地方提供了一个整数。


在您的代码中,您使用 itoa(sec[0],secs,10); 执行此操作是有问题的。 itoa 函数签名是:

char * itoa ( int value, char * str, int base );

您为参数 char * str 提供了 secs,这是一个 uint16_t(16 位整数)。这是一个错误,因为它需要对象的地址,但您提供了一个数字。


要解决此问题,您需要停止为指针参数提供整数。

有关如何将 DS1307Read 的输出转换为显示字符串的帮助,post 专门询问了一个问题。

所以这里有一个完全不同的问题答案,在更高的层次上,为了阐明这一点,我们将从 C 编程中退后一步,讨论建造房屋。我们将向建造房屋的人发出指示,但我们将想象我们有一些严格的、编码的方式来做这件事,有点像函数调用。

假设是时候粉刷房子的外面了。假设有一个 "function" paint_the_house() 看起来像这样:

paint_the_house(char *main_color, char *trim_color);

你决定在黄色的房子里要白色 trim,所以你 "call"

paint_the_house("white", "yellow");

油漆工尽职尽责地把房子刷成白色和黄色 trim。哎呀!你弄错了,没人发现,现在房子颜色不对。

假设还有另一个函数,finish_the_floors(),看起来像这样:

finish_the_floors(char *floor_material, char *color)

floor_material 参数应该是一个字符串,如 "hardwood"、"carpet"、"linoleum" 或 "tile"。你决定要在你的房子里铺上红色瓷砖地板,所以你打电话给

finish_the_floors("red", "tile");

但是安装地板的人回来说,"Listen, buddy, 'red' is not a floor material, and 'tile' is not a color, so do you want to try that again?"这次有人发现了你的错误。

最后,假设有一个函数

furnish_the_bathroom(char *bath_or_shower, int number_of_sinks)

其中 bath_or_shower 应该是字符串 "bathtub" 或 "shower",第二个参数应该是你想要的接收器的数量。您决定要两个水槽和一个浴缸,然后继续您粗心大意的方式,您调用:

furnish_the_bathroom(2, "bathtub");

这一次,你的伪造 "function call" 甚至连要建造浴缸的人都没有。这位建筑师的灯泡昏暗的侄子,他的兄弟骗他在夏天雇用了他,他甚至分不清烤箱和二乘四的区别,他被任命负责将你的指令传递给劳动者,甚至他也能看出不对劲。 "Um, wait a minute," 他发牢骚。 "I thought the first thing was supposed to be a string, and the second thing was supposed to be a number?"

现在我们可以回到你的问题,因为这基本上就是这里发生的事情。当您调用一个函数时,您必须以正确的顺序传递正确的参数(就像您对构建器的说明一样)。编译器无法捕捉到你所有的错误,但它至少可以注意到你正在做一些不可能的错误,比如在你应该传递指针的地方传递一个 int。