473,385 Members | 1,593 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

More problems with sprintf?

[Repost in new thread, as a forum bump doesn't seem to work :)]

Having discovered sprintf (see here), I realised that it was idea for my time conversion function, see this thread. So I took the plunge, and converted it, and it worked for a while, but now something has gone wrong!

This function is passed an integer number of seconds, and returns a text string " HH:MM" derived from it. But it doesn't work anymore; I guess I'm doing something dumb!

Note that txt4[4] and txt7[7] are global scratchpad variables.

Expand|Select|Wrap|Line Numbers
  1. char * formatHours(int seconds) 
  2. { // convert integer seconds timer to string: " HH:MM" 
  3.   byte hrs, mins ; 
  4.   int fullmins ; 
  5.   char time[7] = " " ;  // leading space 
  6.  
  7.  
  8.   fullmins = seconds / 60 ; // convert seconds to minutes 
  9.   hrs =  fullmins / 60 ;    // convert minutes into hours 
  10.   mins = fullmins % 60 ;    // remainder of same division is minutes 
  11.  
  12.   sprintf(txt4, "%02d", hrs) ;    // format 2 places, leading zero 
  13.   strcat(time, txt4) ;   // add to time string 
  14.   strcat(time, ":") ;    // add a colon 
  15.  
  16.   sprintf(txt4, "%02d", mins) ;  // format 2 places, leading zero 
  17.   strcat(time, txt4) ; // 
  18.  
  19.   return (strcpy(txt7, time)) ; 
The calls to sprintf() return the value 3, so that bit is working. But the function returns something like "255:256"
Mar 14 '10 #1
13 4359
Banfa
9,065 Expert Mod 8TB
For what input value do you get that behaviour?

Also you should be able to do the whole thing with a single call to sprintf.
Mar 14 '10 #2
The initial call to the function starts with 0, then increments every second. I let it run for a couple of minutes while I checked my code; does it look OK?

Yes, I'm sure I could do it with a single call, but I'm eating my elephant one byte at a time :)
Mar 14 '10 #3
Banfa
9,065 Expert Mod 8TB
The code looks ok apart from the fact the the time array and txt7 are not nearly long enough to deal with the maximum values you might get.

Hours is seconds / 60 / 60, seconds is an int so the maximum value of hours (assuming a 32bit int is1193046 and this can be positive or negative so the maximum number of characters for the hours field is 8. Minutes is seconds / 60 % 60 so its maximum value is 59 again either positive or negative so its maximum field width is 3. Plus a space character plus a colon plus a NULL terminator means your minimum buffer size for time[] and txt7[] should be

BufferSize = 8 + 3 + 1 + 1 + 1 = 14

Twice as long as the 7 bytes provided by your program. In fact the output you have "255:256" is 8 bytes long and overruns the buffer length causing undefined behaviour in your program.

255 is a completely plausible value for hours given either enough running time or incorrect calling code passing the wrong value into the function.

256 for minutes is much harder to explain. You haven't said, IIRC, if this program is single threaded or multi-threaded and you are unnecessarily using the global buffer txt4 and txt7 is also not allocated locally allowing any part of your program to alter it. At this time some sort of buffer corruption (or accidental reuse) seems like the most obvious explanation for the minutes value.
Mar 14 '10 #4
Thanks for your reply, but I'm a bit confused. I thought the sprintf buffer had to be large enough to contain the string that is returned? This would never be more than two characters: 59 minuits, or 24 hours. It certainly never got past a couple of minutes in testing.

There is a single thread, and I have checked the value of the return value before it returns, still wrong. In fact the values of the buffer just after the sprintf calls are also wrong. However, I did try a new variable as buffer of size 15 (the documentation said this could be necessary), same result.
Mar 14 '10 #5
Banfa
9,065 Expert Mod 8TB
You are right, the sprintf buffer does have to be large enough to contain the returned buffer. It is your responsibility as the programmer to make sure that this constraint is met, sprintf has no way of knowing the size of the buffer it has been passed a pointer to it will just write as many characters as the format string and data require and if the buffer is not big enough then it will write outside the limits of the buffer causing undefined behaviour. The buffer you were supplying was not long enough to hold the maximum output of sprintf given the range of possible inputs to your function.

That is not the range of inputs you are expecting but the absolute maximum which in the case of your program happens if formatHours is passed a value -2147483648. However unlikely this is it is within the accepted range of values of your function and this is the value that gives the largest buffer usage; " −596523:-74"

It is important to oversize the buffer like this because you want to avoid any possibility of undefined behaviour which when it starts causing problems can be really hard diagnose.

I think you are probably going to have to get the value of seconds that are producing the erroneous output, either using a debugger or by putting it into the buffer allong with the converted values.
Mar 15 '10 #6
Banfa
9,065 Expert Mod 8TB
BTW, are you defining byte as

typedef short byte;

or

typedef unsigned short byte;

?

This is almost certainly contributing to your problems as you are doing all your calculations using int and then storing results in short or unsigned short values. Changing hrs and mins to int might make it a bit more obvious where the error is but I remain convinced that the values you are passing to formatHours are in an odd range that you are not expecting.
Mar 15 '10 #7
OK, so the sprintf buffer needs to be long enough to hold the possible values of my type byte (unsigned char). The mins calculation limits this to 59, and the hours is unlikely to get above 12 or so. Even if it did, it can't go above 255, so I figured that a buffer of 4 was OK. I'll try a longer buffer and report back.

The value of seconds starts at 0, and increments every second. After a couple of minutes, (with a value of around 150) the function is still returning "255..."
Mar 15 '10 #8
Banfa
9,065 Expert Mod 8TB
How do you know the value of seconds is 150? Do you print it out or view it with a debugger?

Again I find it hard to believe that byte is unsigned char since mins is a byte and mins gets a value of 256 (although I am hard pressed to work out how) and 256 is out of range for a char either signed or unsigned. I am assuming your platform has 8 bit chars, is this true?
Mar 15 '10 #9
donbock
2,426 Expert 2GB
  • Change the type for hrs and mins from 'byte' to 'int'.
  • Add a trap at the front of your program for the case when the input seconds is negative.
  • Add a trap at the front of your program for the case when hrs is bigger than you think it should be (ie, when it is greater than or equal to 100).
  • Change function prototype so the caller provides the buffer to build the string in (to do that the caller should pass a pointer to the output buffer and its length). Caller can go ahead and specify txt7 if you wish, but your function ought not to assume some particular global buffer for its output.
  • txt4 should be an automatic variable instead of a global.
    'time' is a reserved name; think of something else to call that variable.
  • Explicitly check for and prevent overflow of the output buffer.
Mar 15 '10 #10
Curiouser and curiouser ...

I have created a new buffer (char zonk[15]), turned off the interrupts, removed all the other processing, and hard coded 23 and 59 into the calls to sprintf.

Expand|Select|Wrap|Line Numbers
  1. char * formatHours(int seconds) // argument ignored for test
  2. { // convert integer seconds timer to string: " HH:MM"
  3.    char zonk[15] ; // buffer with odd name to make sure it is unique
  4.  
  5.   sprintf(zonk, "%02d", 23) ;    // hrs format 2 places, leading zero
  6.   strLCD5XY(zonk, 0, 2) ; // print on screen -> displays "279" *****
  7.  
  8.   sprintf(zonk, "%02d", 59) ;  // mins format 2 places, leading zero
  9.   strLCD5XY(zonk, 44, 2) ;  // print on screen -> displays "315" *****
  10.  }
Still not working, see ***** above.
Mar 15 '10 #11
donbock
2,426 Expert 2GB
@nigelmercier
So it doesn't work when you pass an integer constant ...
  • sprintf doesn't work; or
  • strLCD5XY doesn't work
Did sprintf come with your compiler? If so, then I suggest you take a close look at strLCD5XY. Are you sure you're passing the right arguments to it? Are you sure some other part of your code isn't corrupting the display after this snippet does the right thing?
Mar 15 '10 #12
jkmyoung
2,057 Expert 2GB
It is odd that those values are exactly 256 greater than the value passed in.
Mar 15 '10 #13
@jkmyoung
Yes, that is interesting. It certainly explains why I was getting results like 256:257, as the passed values would have been 0 (hours) and the number of minutes.

The sprintf() function came with my compiler, strLCD5XY() is my own function, but simply takes a string argument and displays it at co-ordinates x, y. It has worked fine until now, and is used throughout the project.
Mar 16 '10 #14

Sign in to post your reply or Sign up for a free account.

Similar topics

0
by: Bo Peng | last post by:
Dear list, With the help from this list, I have experimented some techniques and I have to say python/c++/swig is wonderful! I still have some questions though: 1. Is there a way to access...
3
by: Christopher Benson-Manica | last post by:
This is starting to seem ridiculous to me :( #include <streambuf> #include <iostream> class TWFileStream : public std::streambuf { private: char cbuf;
5
by: Steve | last post by:
Hi, I have a class called cList as so: template<class T> class cList { // base class for Lists private: protected: vector<T> tListOf; // field list container public: void Add(const T& t)...
2
by: Simon | last post by:
Hi, I have a function that always crashes and I am not too sure why. Here is the code, (and the value that cause the crash). #include <math.h> .... bool ConvertToString( double num, char...
3
by: premmehrotra | last post by:
I am using Access 2000 and Oracle 9.2.0.x on a Windows 2000. I have setup Oracle 9.2 ODBC Driver (I have not yet figured how to set Microsoft's Oracle ODBC driver). I am exporting a table from...
5
by: Lloyd Sheen | last post by:
I have been adding client code manually but upon reading some of the docs I notice that I should be able to create the stub for events in client script using the IDE menus. Now this would save...
14
by: multiformity | last post by:
So I have been working on an opensource project for a while, and decided to really try to make it look better after focusing on the functionality most of this time. Up to now, I have simply used a...
3
by: Dave | last post by:
Hello everyone, its me again. I have been stuck on this problem forever, and cannot find any documentation or any help to solve it. From what I have seen online, what I need to do should be...
5
by: Chris | last post by:
I was having problems using my local IIS to display asp.net pages, or any pages for that matter. I actually reinstalled IIS and then uninstalled the ..net framework and reinstalled it. All pages...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.