【问题标题】:makes pointer from integer without a cast... DS1307, RTC, BCD从整数生成指针而不进行强制转换... DS1307,RTC,BCD
【发布时间】:2016-04-12 22:19:39
【问题描述】:

我知道以前有人问过这个问题。它遍布谷歌和这个网站,但当他们解释时我无法理解。我已经花了太多时间试图理解,但我仍然不明白,所以请尝试理解有一些基本的东西我不理解......我们开始吧。

在 Proteus 上使用 C 语言编程时,我经常收到警告和/或错误(在本例中为警告):

makes pointer from integer without a cast

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

另外,我得到了很多。是否有可能在没有强制转换的情况下从其他类型的变量中获得此警告?一个角色?我现在如何解决这个问题,并在将来避免它?

这是上下文...

#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]='\0';
     itoa(sec[0],secs,10);

     USART_putstring(secs); // place string in buffer

还有两个错误:

../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

【问题讨论】:

  • 您能解释一下您要对以sec[0]= 开头的行做什么吗?我的回答假设您试图将值 sec[0] (将从 015)写为字符串,并且您还有其他目的来分配 sec[1]sec[2] 稍后将使用它们.
  • 评论 Read seconds address 应该是 Read seconds。您正在读取秒数,而不是任何地址。
  • 这是一个时钟。 sec[0] 是右边的秒数。 sec[1] 是左边的秒数。然后我转换为一个字符串,然后需要通过 USART 发送它。我将需要继续将东西连接到我发送的发送。这将是全职和另一个发送日期的选项。时间来自 DS1307 读取。
  • 你现在的写法;假设ss = 30,那么您将获得sec[0] = 14sec[1] = 1sec[2] = 0。在ss = 30 的情况下,您是否真的尝试将文本30 发送到USART?
  • 如果您的问题包括示例输入和您期望的输出,这将有所帮助

标签: c pointers casting type-conversion real-time-clock


【解决方案1】:

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

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

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

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

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

希望对您有所帮助。

【讨论】:

  • 好的,这太棒了。但是你说'itoa 需要一个指向其第二个参数的内存位置的指针',然后说'char secs [3]',然后说'itoa(sec [0],secs,10);'那行得通,但是如何! secs 不是地址, secs[0] 是。这就是我可以看到的工作,但这不起作用。我不明白。编辑:我可以这样做,但这会使它复杂化,因为秒需要数字。我以为我可以将第一个,第二个,然后将 \0 排列到秒数组,因此,sec[3]。
  • @TomiFodor secs[0] 不是地址。它是单个字符。 &amp;secs[0] 将是一个地址。 C 中有一条规则,如果您在需要地址的地方写下数组的名称,编译器会假装您写的是 &amp;name[0]
  • 是的,对不起 - 我应该解释一下。感谢您的澄清,@M.M!
【解决方案2】:

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

假设是时候粉刷房子的外部了。假设有一个“函数”paint_the_house(),看起来像这样:

paint_the_house(char *main_color, char *trim_color);

你决定要在黄色房子上装饰白色装饰,所以你“打电话”

paint_the_house("white", "yellow");

画家们尽职尽责地把房子漆成白色和黄色装饰。哎呀!你弄错了,没人发现,现在房子颜色不对。

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

finish_the_floors(char *floor_material, char *color)

floor_material 参数应该是一个字符串,如“硬木”、“地毯”、“油毡”或“瓷砖”。你决定要在你的房子里铺红色瓷砖地板,所以你打电话

finish_the_floors("red", "tile");

但是安装地板的人回来说:“听着,哥们,‘红色’不是地板材料,‘瓷砖’不是颜色,你想再试一次吗?”这一次,有人发现了你的错误。

最后,假设有一个函数

furnish_the_bathroom(char *bath_or_shower, int number_of_sinks)

其中bath_or_shower 应该是字符串“浴缸”或“淋浴”,第二个参数应该是您想要的水槽数量。你决定要两个水槽和一个浴缸,然后继续你粗心的方式,你打电话:

furnish_the_bathroom(2, "bathtub");

这一次,你的虚假“函数调用”甚至没有传给要建造浴缸的人。建筑师的昏暗的侄子,他的兄弟诱使他在夏天雇用他,甚至无法区分烤箱和二乘四的区别,他负责将您的指示转达给劳动者,就连他也能看出哪里不对劲。 “嗯,等一下,”他抱怨道。 “我以为第一件事应该是一个字符串,第二件事应该是一个数字?”

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

【讨论】:

    【解决方案3】:

    这意味着编译器会隐式为您转换它,但是,它会通过发出警告来通知您它所做的,以便您知道这一点。

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

    float f = 1.0;
    int i = f;
    

    根据平台、语言和编译器设置,可能会出现以下几种情况:

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

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

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

    void USART_putstring(char* StringPtr)

    无需进一步研究,将int 传递给期望char* 的函数(如果是这种情况),“可能”会产生意想不到的结果。

    解决方案

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

    编辑:

    动画1

    +1

    确保您也了解“整数”和“指向整数的指针”之间的区别,他解释得很好:)

    【讨论】:

      【解决方案4】:

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

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

      将整数转换为指针是错误的,反之亦然,除非您编写 cast 来表示“我知道我在这里做什么”。

      不幸的是,一些编译器会吐出“警告”,然后生成一个伪造的二进制文件。如果可能的话,看看你是否可以使用编译器开关,让编译器在这种情况下说“错误”。

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


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

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

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


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

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

      【讨论】:

      • 那么来自 sec[0] 的整数不只是进入 &secs_buf[0] 的地址吗?它们应该只是从 0 到 9 的整数。在这种情况下,它不会只有 7 位长吗? ASCII 对吗?
      • 没有任何东西进入“地址”。东西进入对象。地址是你可以用来告诉代码的另一部分对象在哪里的东西。借用 Steve Summit 的例子,你的邮件在你的信箱里,而不是在你的地址里(这甚至没有意义)。你似乎不清楚一个对象那个对象的地址之间的区别——试着把这些东西放在你的脑海里
      • 在您的原始代码中,0b00001111 &amp; ss 选择最后 4 个 二进制数字(不是您尝试做的最后 1 个十进制数字),从 @987654329 生成一个整数值@ 到 15(不是数字)
      • 不过它不会超过 9。位 0 到位 3 存储 RTC 的单个数字
      • @TomiFodor 你是说这个值是 BCD(二进制编码的十进制?)如果是这样,这个信息应该在你的问题中(你的代码仍然没有给出数字)跨度>
      猜你喜欢
      • 2021-01-19
      • 2023-02-08
      • 2022-01-05
      • 1970-01-01
      • 2012-06-09
      • 2017-05-06
      • 1970-01-01
      • 2021-07-12
      • 1970-01-01
      相关资源
      最近更新 更多