0

I know this question has been asked before. It's all over Google and on this site too, but I can't understand people when they explain it. I have already spent far too many hours trying to understand and I still don't so please try to understand that there's something fundamental I am NOT understanding... here we go.

When programming in C on Proteus, I often get the warning and/or error (in this case warning):

makes pointer from integer without a cast

and I don't get it. Like I said, I've already spent hours looking into it and I get it has to do with types, and/or pointers, blah. Someone please explain it to me like a normal person.

Also, I get this a lot. Could it be possible to get this warning from other types of variables without a cast? A character? How would I go about fixing this problem now, and avoiding it in the future?

Here's the context...

#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

and the 2 errors:

../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
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Tomi Fodor
  • 15
  • 6
  • Could you explain what you are trying to do with the lines starting `sec[0]=` ? My answer assumes you were trying to write as a string the value `sec[0]` (which will be from `0` to `15`) , and you have some other purpose for assigning `sec[1]` and `sec[2]` which you will use later. – M.M Apr 12 '16 at 22:50
  • The comment `Read seconds address` should say `Read seconds`. You are reading the number of seconds, not any address. – M.M Apr 12 '16 at 22:58
  • It's a clock. The sec[0] is the seconds digit on the right. sec[1] is the seconds digit on the left. I then convert to a string, then need to send that through the USART. I'm going to need to keep connecting stuff onto the send of what I am sending out. It's going to be full time and another option to send date. The time comes in from DS1307 reads. – Tomi Fodor Apr 12 '16 at 23:14
  • The way you have written it now; let's say `ss = 30`, then you will get `sec[0] = 14` and `sec[1] = 1` and `sec[2] = 0`. Are you actually trying to send the text `30` to the USART in the case where `ss = 30` ? – M.M Apr 12 '16 at 23:18
  • It would help if your question included sample input and the output you expect – M.M Apr 12 '16 at 23:20
  • If I understand what you are asking, then the answer is yes. Yea I'm a pretty huge nooby, perhaps I'm making this way harder than it needs to be. Right now I'm just sending seconds, but I need to save it into a data packet (seconds, minutes, everything) to send it out the USART. The format would be "ssAmmBhhCddDmmEyyFxG" with the caps letter just fillers. x would be the mode, whether time or date. – Tomi Fodor Apr 12 '16 at 23:23
  • suggest rolling back the last update and making a new question, this is turning into a big mess. You have two completely separate issues here (1. what does "convert pointer to integer without a cast" mean, and 2. how do I do what I am trying to do") , you should stick to one issue per question. There are already many answers posted answering question 1, so do not change the question now. – M.M Apr 13 '16 at 00:52
  • Ok so because I had more issue than 1 I get a -1? Cool. – Tomi Fodor Apr 13 '16 at 01:11

4 Answers4

2

Your compiler is telling you that the function expects a pointer, but you've passed an integer. So it's going to automatically treat your integer value as an address and use that as the pointer.

For example, itoa expects a pointer to a memory location for its second parameter - that's where it stores the resulting string that it builds from the integer you pass it. But you've passed secs for that - a uint16_t. The compiler is warning you that whatever value is in that integer is going to be used as the address where itoa puts its resulting string.

This kind of thing would cause a segfault on most targets, but I'm not familiar with Proteus.

Anyway, as an example, to fix the itoa warning, use something like the following:

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

Hope that helps.

Aenimated1
  • 1,594
  • 1
  • 9
  • 10
  • Ok sure that's awesome. But you said 'itoa expects a pointer to a memory location for its second parameter', then say 'char secs[3]', and then 'itoa(sec[0], secs, 10);' That works, but how!? secs is not an address, secs[0] would be. That's what I could see working, but that doesn't work. I don't get it. edit: I can do that but it would complicate it because seconds needs to digit. I thought I could just array the first, second, and then \0 to the seconds array, hence, sec[3]. – Tomi Fodor Apr 12 '16 at 22:52
  • 1
    @TomiFodor `secs[0]` is not an address. It is a single character. `&secs[0]` would be an address. There is a rule in C that if you write the name of an array where an address is expected, the compiler pretends that you had written `&name[0]` instead. – M.M Apr 12 '16 at 22:59
  • Yes, sorry - I should have explained that. Thanks for clarifying, @M.M! – Aenimated1 Apr 12 '16 at 23:03
1

It means that the compiler implicitly casts it for you, however, it notifies you it did by emitting a warning so you know that.

Here's an example using numbers:

float f = 1.0;
int i = f;

Depending the platform, language and compiler settings a couple of scenarios are possible:

  • compiler implicitly casts float to int without a warning (bad)
  • idem but issues a warning (better)
  • compiler settings changed to treat warnings as errors (safe, security critical etc...)

Warnings are a good hint on possible bugs or errors and it's generally wise to fix them instead of suppressing or ignoring them.

In your specific case, I've been looking for an USART_pustring and the first I've found was this one :

void USART_putstring(char* StringPtr)

No need to look further, passing an int to a function expecting char* (if this is the case), 'might' produce an unexpected result.

Solution

Read the documentation of USART_putstring and ensure you 'transform' your input data to the correct type it accepts, the warning will vanish by itself.

EDIT:

+1 for Aenimated1

Ensure that you understand what are the differences between 'integer' and 'pointer to integer' too, he explained that rather well :)

aybe
  • 15,516
  • 9
  • 57
  • 105
1

Integers are for counting. Pointers are an abstract indication of where a variable may be found.

To keep things clear in your head it is a good idea to not mix up the two, even if you are on a system where the concrete implementation of a pointer is the same as the implementation of an integer.

It is an error to convert integer to pointer or vice versa, unless you write a cast to say "I know what I'm doing here".

Unfortunately some compilers will spit out "warning" and then generate a bogus binary. If possible, see if you can use compiler switches that will make the compiler say "error" for this case.

If you see this error it usually means that you supplied an integer where the compiler was expecting you to supply a pointer.


In your code, you do this with itoa(sec[0],secs,10); is a problem. The itoa function signature is:

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

You supplied secs, which is a uint16_t (a 16-bit integer), for the parameter char * str. This is an error because it expects the address of an object, but you supplied a number.


To fix this you need to stop supplying integers for parameters that are pointers.

For assistance with how to convert the output of DS1307Read to a display string, post a question asking about that specifically.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • So the integer from sec[0] doesn't just go into the address of &secs_buf[0]? They should only be integers from 0 to 9. Wouldn't, in this case, it only be 7 bits long? ASCII right? – Tomi Fodor Apr 12 '16 at 23:28
  • Nothing goes "into the address". Things go into the object. The address is something you can use to tell another part of the code where an object is. Borrowing Steve Summit's example, your mail goes in your letterbox, not in your address (which doesn't even make sense). You seem to be unclear on the difference between *an object* and *the address of that object* - try to get those things straight in your head – M.M Apr 12 '16 at 23:37
  • In your original code `0b00001111 & ss` selects the last 4 *binary digits* (not the last 1 decimal digit as you were trying to do), making an integer value from `0` to `15` (not a digit) – M.M Apr 12 '16 at 23:37
  • It doesn't go above 9 though. bits 0 to bit 3 store the single digit of the RTC – Tomi Fodor Apr 13 '16 at 00:26
  • @TomiFodor are you saying that the value is in BCD (binary-coded decimal?) If so, this info should be in your question (and your code still doesn't give a digit) – M.M Apr 13 '16 at 00:37
  • You should really post a separate question about how to convert your clock into a string. It is nothing to do with the error in the topic really. I will edit my answer to stay on topic. – M.M Apr 13 '16 at 00:42
  • Ok my apologizes, I didn't think that was important information at the time. I've been getting confused myself, but it is represented as a BCD. I'm not to stack overflow, should I keep posting on this? I've changed the code up A LOT, so think the initial post should be updated. The snprint function does word, same with sprint, but it gives a warning `../main.c:81: warning: implicit declaration of function 'snprintf' ../main.c:81: warning: incompatible implicit declaration of built-in function 'snprintf'`. – Tomi Fodor Apr 13 '16 at 00:42
  • use `#include ` to avoid that error (which is an error despite the word "warning" - you should treat all compiler messages as errors unless you know for 100% sure what is happening) – M.M Apr 13 '16 at 00:44
  • I would recommend starting a new question , if you are still unsure how to produce a string with the right output. The title should be "How do I convert DS1307 RTC time to a string" or something, and in the question you should show the code you tried and also explain what the output of the `DS1307Read` function is **exactly**, so that readers who don't know what a DS1307 is can still help. I managed to find some by googling ([here](http://extremeelectronics.co.in/avr-tutorials/interfacing-ds1307-rtc-chip-with-avr-microcontroller/)) but your question should include such info or links already. – M.M Apr 13 '16 at 00:47
1

So here's a completely different answer to the question, at a much higher level, and to make the point clear, we're going to take a step back from C programming and talk about building houses. We're going to give instructions to the people building the house, but we're going to imagine we have some rigid, codified way of doing it, sort of like function calls.

Suppose it's time to paint the outside of the house. Suppose there's a "function" paint_the_house() that looks like this:

paint_the_house(char *main_color, char *trim_color);

You decide you want white trim on a yellow house, so you "call"

paint_the_house("white", "yellow");

and the painters dutifully paint the house white with yellow trim. Whoops! You made a mistake, and nobody caught it, and now the house is the wrong color.

Suppose there's another function, finish_the_floors() that looks like this:

finish_the_floors(char *floor_material, char *color)

The floor_material argument is supposed to be a string like "hardwood", "carpet", "linoleum", or "tile". You decide you want red tile floors in your house, so you call

finish_the_floors("red", "tile");

But the guy who installs the floors comes back and says, "Listen, buddy, 'red' is not a floor material, and 'tile' is not a color, so do you want to try that again?" This time, someone caught your mistake.

Finally, suppose there's a function

furnish_the_bathroom(char *bath_or_shower, int number_of_sinks)

where bath_or_shower is supposed to be the string "bathtub" or "shower", and the second argument is supposed to be the number of sinks you want. You decide you want two sinks and a bathtub and, continuing your careless ways, you call:

furnish_the_bathroom(2, "bathtub");

This time, your bogus "function call" doesn't even make it to the guy who's going to build the bathtub. The architect's dim-bulb nephew, who his brother conned him into hiring for the summer, who can't even tell the difference between a toaster oven and a two-by-four, he's been put in charge of relaying instructions from you to the laborers, and even he can see that there's something wrong. "Um, wait a minute," he whines. "I thought the first thing was supposed to be a string, and the second thing was supposed to be a number?"

And now we can go back to your question, because that's basically what's going on here. When you call a function, you have to pass the right arguments in the right order (just like your instructions to the builders). The compiler can't catch all your mistakes, but it can at least notice that you're doing something impossibly wrong, like passing an int where you're supposed to pass a pointer.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103