C- while loop un-explained behaviour - c

I am trying to run the following code :
#include <sys/time.h>
#include <stdio.h>
int main()
{
unsigned int ms, oldms = 0,dif;
struct timeval tv;
while(1)
{
gettimeofday(&tv, NULL);
ms=tv.tv_sec;
//printf("%d\n",ms-oldms );
dif=ms-oldms;
if(dif>3)
{
printf("3 seconds up");
oldms=ms;
}
}
}
I am expecting it to print "3 seconds up" after every 3 seconds, but it doesn't display that message.
I tried to debug it using gdb but nothing seems wrong and still no output.
While trying to debug, I added a printf statement and magically the output can be seen.
If I run the program after removing the //printf("%d\n",ms-oldms ); statement , there is no output again.I am not sure what's happening and whether its dependant on anything.
$gcc --version
gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2

Output buffering is the reason.
stdout is line buffered by default when attached to a terminal device. You can flush this out using fflush(stdout); or using \n in printf() i.e. printf("3 seconds up\n");.
or disabling it with setbuf(stdout, 0);
I/O is slow in general. So implementations use a fixed size buffer and printf once it gets full.
In practice, calling fflush(stdout); too often can affect performance.

the posted code has a couple of problems
the variable oldms is not being set to any specific value before the elapsed time is being checked
without either a call to fflush(stdout); or a trailing newline ('\n') in the format string, nothing will be output (for a very long time, until the system stdout buffer is filled)
for readability, the axiom only one statement per line and (at most) one variable declaration per statement is applied to the code
the following code compiles cleanly and performs the desired operation
#include <sys/time.h>
#include <stdio.h>
int main()
{
unsigned int ms;
unsigned int oldms = 0;
unsigned int dif;
struct timeval tv;
gettimeofday(&tv, NULL);
oldms = tv.tv_sec;
while(1)
{
gettimeofday(&tv, NULL);
ms=tv.tv_sec;
//printf("%d\n",ms-oldms );
dif=ms-oldms;
if(dif>3)
{
printf("3 seconds up\n");
oldms=ms;
}
}
} // end function: main

Related

Only updating the displayed time elapsed when the time change in C

I would like to display the seconds elapsed after the start of program:
volatile time_t start_time = time(NULL);
volatile time_t target_seconds = 60*60*17;
volatile time_t time_passed = 0;
while(1)
{
time_passed = time(NULL)-start_time;
printf("\rTime elapsed=%lu/%lu(seconds)", time_passed, target_seconds);
}
Output:
Time elapsed=1/61200(second)
But it will keep updating the display no matter what value time_passed is.
Now I only want to update the displaying time elapsed when the actual time is incremented.
So I changed the program in this way:
volatile time_t start_time = time(NULL);
volatile time_t target_seconds = 60*60*17;
volatile time_t time_passed = 0;
while(1){
if ((time(NULL)-start_time) != time_passed)
{
time_passed = time(NULL)-start_time;
printf("\rTime elapsed=%lu/%lu(seconds)", time_passed, target_seconds);
}
}
Now it displays nothing.
Can anyone explain why and how to solve it.
Your code is fine.
But depending on your platform the output buffer is flushed only when a \n is printed.
Therefore you should add fflush(stdout); right after the printf.
if ((time(NULL)-start_time) != time_passed)
{
time_passed = time(NULL)-start_time;
printf("\rTime elapsed=%lu/%lu(seconds)", time_passed, target_seconds);
fflush(stdout);
}
BTW: if you wait long enough, you'll end up seeing some output because eventually the output buffer will be full and then everything will be displayed at once, which of course doesn't make much sense here.
The reason why you see immediately output with the first version of your code is that your're printing contiuously and therefore the output buffer will be full very quickly, and it will be flushed contiuously hence you see output.
The volatile keyword is not required here, it's absolutely unnecessary but it doesn't harm either.
Apart from calling fflush after every printf it's also possible to turn off buffering on stdout. use either setbuf or setvbuf
#include <stdio.h>
setbuf(stdout, NULL);
setvbuf(stdout, NULL, _IONBF, 0);
Now every character will get printed

Forcing a terminal not to print Ctrl hotkeys when signals are caught

Good day,
I'm writing my own shell in C for my school which has to resemble bash as closely as possible.
I have to handle signals such as Ctrl-\ and Ctrl-C as bash does; for this reason I'm allowed to use signal function. It works fine, but the thing is whenever a Ctrl-C signal is caught (starting from the second catch), a ^C is printed.
On the net, I've found a workaround suggesting printing "\b \b\b \b\nminishell$ " whenever a Ctrl-C is caught, which will devour the two symbols. The thing is, since at the very first time ^C is not printed, the print devours two symbols of my prompting, making it just minishell instead of minishell$ , with the cursor incorrectly displayed.
Now I've come up with another workaround for this workaround which is to declare a static boolean to not print the baskspaces at the very first call. This doesn't help in case of Ctrl-\ though; Ctrl-\ proceeds to move my cursor to right when I attempt to write the two whitespaces that must replace the ^\.
I don't like these workarounds and would like to know whether there is a way to instruct the terminal not to output this stuff? I'm allowed to use tgetent, tgetflag, tgetnum, tgetstr, tgoto, tputs, tcsetattr, tcgetattr, have read their man pages but nothing seems to be helpful.
When you type a key on a terminal, two things happen
the character is echoed (displayed) on this terminal
the character is sent (over the line) to the attached program
Both these actions can be controlled via termios/tcsetattr(): a different character(s) can be sent or echoed, some can be suppressed, etc. (some/most of these actions take place in the terminal-driver , but this is not relevant here)
Demonstration: using tcsetattr() to control the echoing of the terminal:
#include <stdio.h>
#include <stdlib.h>
#define _SVID_SOURCE 1
#include <termios.h>
#include <unistd.h>
#include <signal.h>
struct termios termios_save;
void reset_the_terminal(void)
{
tcsetattr(0, 0, &termios_save );
}
sig_atomic_t the_flag = 0;
void handle_the_stuff(int num)
{
char buff[4];
buff[0] = '[';
buff[2] = '0' + num%10;
num /= 10;
buff[1] = '0' + num%10;
buff[3] = ']';
write(0, buff, sizeof buff);
the_flag = 1;
}
int main (void)
{
int rc;
int ch;
struct termios termios_new;
rc = tcgetattr(0, &termios_save );
if (rc) {perror("tcgetattr"); exit(1); }
rc = atexit(reset_the_terminal);
if (rc) {perror("atexit"); exit(1); }
termios_new = termios_save;
termios_new.c_lflag &= ~ECHOCTL;
rc = tcsetattr(0, 0, &termios_new );
if (rc) {perror("tcsetattr"); exit(1); }
signal(SIGINT, handle_the_stuff);
printf("(pseudoshell)Start typing:\n" );
while(1) {
ch = getc(stdin);
if (the_flag) {
printf("Saw the signal, last character was %02x\n", (unsigned) ch);
break;
}
}
exit (0);
}
The way to set the console such a SW may intercept all typed chars is to set the terminal in RAW MODE. The problems this way may present are that all keys that aren't in the ASCII 0-255 space, such as è, ì, à will be received from the console as a bytes sequence and all the function and control keys included cursors and backspace will not accomplish any action, some code such as CR, LF and some ANSI sequence may accomplish actions when are read from the input channel and rewritten on the output channel.
To set the terminal in raw mode you have to use the function cfmakeraw followed by the function tcsetattr.
The code below implements a simple but not very good implemented terminal, anyway I think this code is a good point to start. In any case, the code flow and the error control must be at least better arranged.
The code writes all sequence of ASCII char that enter into the console when a key is typed. All chars that have value smaller then 32 or greater then 126 will be written as [HEX-CODE]
I.E. hitting Esc on the console will be written [1B], the code of Ctrl+C will be written as [03], F1 will be [1B]OP, F11 will be [1B][23~, Enter will be [0D].
If you will hit Ctrl+X [18] will be written and the program stops, but this behaviour is under SW control as you can see in the code.
Here the code:
#include <stdio.h> // Standard input/output definitions
#include <string.h> // String function definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
#include <errno.h> // Error number definitions
#include <termios.h> // POSIX terminal control definitions (struct termios)
#include <sys/ioctl.h> // Used for TCGETS2, which is required for custom baud rates
#include <sys/select.h> // might be used to manage select
int setAttr(int ch, int resetToOld);
#define IN 0
#define OUT 1
typedef struct TermCap
{
int fd;
struct termios oldTermios;
struct termios newTermios;
// fd_set fds; // might be used to manage select
} TermCap;
TermCap m_termCap[2];
int main()
{
int i,ex=0;
char msg;
char buff[20];
m_termCap[IN].fd=STDIN_FILENO;
m_termCap[OUT].fd=STDOUT_FILENO;
// Gets STDIN config and set raw config
setAttr(IN,0);
// Gets STDOUT config and set raw config
setAttr(OUT,0);
// Console loop ... the console terminates when ^X is intercepted.
do {
do {
i=read(m_termCap[IN].fd,&msg,1);
if (i>0){
if (msg<32 || msg>126) {
sprintf(buff,"[%02X]",(unsigned char)msg);
write(m_termCap[OUT].fd,buff,4);
if (msg==24)
ex=1;
}else{
write(m_termCap[OUT].fd,&msg,i);
}
}
usleep(10000); // a minimal delay of 10 millisec
} while(i>0 && !ex);
} while(!ex);
// Reset console to initial state.
setAttr(IN,1);
setAttr(OUT,1);
printf("\r\n\nThe end!");
return 0;
}
int setAttr(int ch, int resetToOld)
{
int retVal=0;
int i;
if (!resetToOld) {
// Read old term config
i=tcgetattr(m_termCap[ch].fd, &m_termCap[ch].oldTermios);
if (i==-1) {
return 1;
}
}
m_termCap[ch].newTermios = m_termCap[ch].oldTermios;
if (!resetToOld) {
// Terminal in raw mode
cfmakeraw(&m_termCap[ch].newTermios);
}
i=tcsetattr(m_termCap[ch].fd, TCSANOW, &m_termCap[ch].newTermios);
if (i==-1) {
retVal = 2;
}
return retVal;
}
Wouldn't this work?
void signalHandler(int signo){
if(signo==SIGINT){
printf("\b\b \b\b");
fflush(NULL);
printf("\nHello World\n");
}
}
In my shell it seems to work fine. The first printf and fflush is what you have to implement in your handler. The printf after that is just a way for me to show you that you can, then, do whatever you want after the ^C not appearing.
Why does this make it not appear? In the first printf I erase the characters by using backspaces and spaces. As stdout is buffered by default and I didn't want to use a newline character, I flushed the buffer manually.

Timer using a time function in C [duplicate]

This question already has answers here:
Why does printf not flush after the call unless a newline is in the format string?
(10 answers)
Closed 1 year ago.
I want to print a line and then get it erased after ten seconds.
So I thought that I should write a timer as a preliminary programme and with erasure I could deal later using whatever I find on the internet (using \r for example).
And so I want to print "I love nachos" and ten seconds later "I hate nachos".
However, even though printf("I love nachos") is written before any conditions, the programme prints both strings after ten seconds.
#include <stdio.h>
#include <time.h>
int main(void) {
printf("I love nachos");
time_t now = time(NULL);
while (1)
{
time_t future = time(NULL);
if ((future-now)==10)
{
break;
}
}
printf("I hate nachos");
return 0;
}
I asked my friend to tackle the problem and he wrote:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
printf("Start\n");
time_t t0 = time(NULL);
while ( (difftime(time(NULL), t0)) <= 10.0 )
{}
printf("End");
return 0;
}
However, in that case the programme only works with \n in printf("Start\n").
If I remove \n I get the same result as per my initial code and I obviously don't want \n there, because I wouldn't be able to erase the line with \r
The printf output to stdout is by default line buffered. That means nothing is actually sent out until either the internal buffer is full or a newline is added or the FILE is closed (as happens implicitly when the program exits)
So either add a newline or use fflush to force the buffer to be transmitted immediately to the output.

How to make minutes and seconds timer in C

I'm struggling to make a timer in c that counts minutes and seconds. I'm trying to test it by printing the time to the console but it doesn't seem to show anything. Does anything look wrong in my code?
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#define TRUE 1
int main( void )
{
int min = 0;
int sec = 0;
while (TRUE)
{
sec++;
Sleep(1000);
printf("%2d:%2d", min, sec);
if (sec == 59)
{
min++;
sec = 0;
}
}
return 0;
}
For performance reason, printf is buffered. That is, it won't display until the buffer is full. First thing to try is to add a new-line character to the end:
printf("%2d:%2d\n", min, sec);
If that doesn't work, you can force the output buffer to flush by calling fflush(stdout);
I would just check the system time rather than keeping track of seconds/minutes. This is because, your Sleep may not be exactly 1000ms, so over time your counter will not be accurate.
Since you're using Windows, here's a slightly modified version of your code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
int main()
{
for (;;)
{
time_t now = time(NULL);
struct tm* ptm = localtime(&now);
printf("%02d:%02d\n", ptm->tm_min, ptm->tm_sec);
Sleep(1000);
}
return 0;
}
I hope that helps.
As you ask, there are several things wrong in your code, I'll tell you as I read it. See below.
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#define TRUE 1
int main( void )
{
int min = 0;
int sec = 0;
while (TRUE)
{
sec++;
Sleep(1000);
There's a problem with Sleep(). The thing is that you ask the kernel to pause your program for 1000 milliseconds, but that means that the kernel will awake your program 1 second after your call it to pause. This doesn't take into account the fact that the kernel will put in the schedule queue your process and it will, in general never take the cpu immediately, but after some delay. Then, even if you get the cpu immediately, your code will need some time to execute, making the total loop longer than 1000 ms. And your clock will be slow. It is better to get the system time and show it on the screen, or to take a timestamp when you start... and then show the difference in time from the start time to the timestamp you get at each display. The system time is maintained by an interrupt, that happens at regular intervals (by means of a precise clock oscillator) so you'll get a good clock time that way, instead of your slow clock (how slow it is will depend on things like how many other processes you are running on the system)
printf("%2d:%2d", min, sec);
This has already been stated in other answers, but let me explain how it works so you can understand how buffering works. A buffer is a large block of memory (normally it is 512 bytes) that is filled by printf() so it only calls write() when it has filled a complete buffer of data. This allows stdio to save system calls to do the actual writing and so, be more efficient when transferring large amounts of data.
On interactive applications, this is not applicable, as no output would be done if you don't force the buffers to fflush() before any input is done, so when the output is a tty device (something that stdio can know from the file descriptor associated to standard output) then it switches to line mode buffering, and that means that printf() will flush out the buffer when: 1) it is filled up, or 2) when a newline \n character is found in the output. So, one way to solve your problem is to put a \n at the end of the string, or to call fflush(stdout); after calling printf().
if (sec == 59)
as you increment your seconds before comparing, you have to check against 60 and not 59, as you compare with 60 to convert it to 0 after you have already incremented the seconds.
{
min++;
You should have to do the same with the minutes, when minutes get to 60. As you have not included this code, I assume you are not considering an hours chrono.
sec = 0;
}
}
return 0;
}
A complete solution for what I mean can be:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <windows.h>
int main()
{
long start_timestamp;
long display_timestamp;
start_timestamp = time(NULL);
for(;;) { /* this is the same as while(TRUE) */
display_timestamp = time(NULL);
int elapsed = display_timestamp - start_timestamp;
int min = elapsed / 60;
int sec = elapsed % 60;
/* the \r in next printf will make to print a single carry
* return in the same line, so the time updates on top of
* itself */
printf("\r%02d:%02d", min, sec); fflush(stdout);
Sleep(100); /* as you print the time elapsed, you don't
* mind if you shorten the time between
* displays. */
}
}
Does anything look wrong in my code?
Several things look wrong. The first is stdout line buffering - see eduffy's answer for that.
The second problem is that you're doing sec++; sleep(1000);, which means that sec will be incremented once every 1000 seconds or more.
The third problem is that if(sec == 59; is wrong and needs to be if(sec == 60). Otherwise you'll have 59 seconds per minute.
The fourth problem is that sleep(1) will sleep for at least 1 second, but may sleep for 2 seconds, or 10 seconds, or 1234 seconds. To guard against this you want something more like this:
expiry = now() + delay;
while(true) {
sleep(expiry - now() ):
expiry += delay;
}
The basic idea being that if one sleep takes too long then the next sleep will sleep less; and it'll end up being "correct on average".
The last problem is that sleep() doesn't really have enough precision. For 1 second delays you want to be able to sleep for fractions of a second (e.g. like maybe 9/10ths of a second). Depending on which compiler for which OS, there's probably something better you can use (e.g. maybe nanosleep()). Sadly there may be nothing that's actually good (e.g. some sort of "nanosleep_until(expiry_time)" that prevents jitter caused by IRQs and/or task switches that occur after you determine now but before you call something like "nanosleep()").

How can I clear what scanf read?

I want to be able to clear the value of what scanf read in. In other words, I want to delete the value that was read in by scanf.
Here is my sample code:
#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
volatile sig_atomic_t gotsignal;
void handler(){
gotsignal = 1;
}
int main(){
struct sigaction sig;
sig.sa_handler = handler;
sig.sa_flags = 0;
sigemptyset(&sig.sa_mask);
alarm(5);
sigaction(SIGALRM, &sig, NULL);
int value;
while(!gotsignal){
printf("Insert a value: \n");
scanf("%d", &value);
}
}
Output:
Insert a value:
5(dont press enter)[JPS#localhost c]$ 5 <-
Is it possible(if yes how) to clear the 5?
I have been reading about terminal settings, fflushs, stdin, but i couldn't figure it out. Any help please?
EDIT: After a lot of trys i think i found something that works. If anyone has this problem this worked for me(not sure if it works on other systems and stuff, kinda new to this):
#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <termios.h>
#include <unistd.h>
volatile sig_atomic_t gotsignal;
void handler()
{
gotsignal = 1;
}
int main(){
struct sigaction sig;
sig.sa_handler = handler;
sig.sa_flags = 0;
sigemptyset(&sig.sa_mask);
alarm(5);
sigaction(SIGALRM, &sig, NULL);
int value;
while(!gotsignal){
printf("Insert a value: \n");
scanf("%d", &value);
}
printf("\n");
tcflush(STDOUT_FILENO,TCIOFLUSH); <-important bit!
return 0;
}
Output:
Insert a value:
5
Insert a value:
5(no enter was pressed)!
[JPS#localhost c]$ <- NO MORE NR 5! :D
See these links for good answers:
How can I flush pending input so that a user's typeahead isn't read at the next prompt? Will fflush(stdin) work?
If fflush won't work, what can I use to flush input?
To quote the most interesting:
There is no standard way to discard unread characters from a stdio
input stream. Some vendors do implement fflush so that fflush(stdin)
discards unread characters, although portable programs cannot depend
on this. (Some versions of the stdio library implement fpurge or
fabort calls which do the same thing, but these aren't standard,
either.) Note, too, that flushing stdio input buffers is not
necessarily sufficient: unread characters can also accumulate in
other, OS-level input buffers. If you're trying to actively discard
input (perhaps in anticipation of issuing an unexpected prompt to
confirm a destructive action, for which an accidentally-typed ``y''
could be disastrous), you'll have to use a system-specific technique
to detect the presence of typed-ahead input; see questions 19.1 and
19.2. Keep in mind that users can become frustrated if you discard input that happened to be typed too quickly.
You might use the readline library. But I'm not sure to understand what you mean by "clear the 5".
The simplest example might be
// file testrl.c
#include <readline/readline.h>
#include <stdlib.h>
int main ()
{
char bufprompt[20];
char* lin = NULL;
int cnt = 0;
for (;;) {
memset(bufprompt, 0, sizeof(bufprompt));
cnt++;
snprintf(bufprompt, sizeof(bufprompt)-1, "%d: ", cnt);
lin = readline(bufprompt);
if (!lin)
break;
printf("you typed %s\n", lin);
free (lin);
}
return 0;
}
Compile the above with gcc -Wall -g testrl.c -o testrl -lreadline
See also this question

Resources