putchar prints nothing (C learning)

Fabien

Member

Reaction score: 4
Messages: 28

Hi!

Sorry if I am posting this in the wrong place.

I am trying to learn C.

I faced a issue in a code with conio.h and kbhit() and fixed it with a function "unix_text_kbhit(void)" I found on the web. I think I should use ncurses instead, anyway it is not the problem right now.

My issue is that putchar, in main, prints nothing... but it works fine on Linux.

This code is only for a teaching purpose, it is originally written for Windows.

I found mode_raw and unix_text_kbhit on the web to implement kbhit(), I am not able yet to understand them The problem probably comes from unix_text_kbhit since putchar works in others little codes i tried.

May somebody help, please :)


Here is the code:

Code:
#include <stdio.h>
#include <time.h>
#include <unistd.h>   //  kbhit
#include <sys/time.h> //  kbhit
#include <termios.h>  //  raw           
#include <unistd.h>   //  raw           

void mode_raw(int activer)
{
    static struct termios cooked;
    static int raw_actif = 0;

    if (raw_actif == activer)
        return;

    if (activer)
    {
        struct termios raw;

        tcgetattr(STDIN_FILENO, &cooked);

        raw = cooked;
        cfmakeraw(&raw);
        tcsetattr(STDIN_FILENO, TCSANOW, &raw);
    }
    else
        tcsetattr(STDIN_FILENO, TCSANOW, &cooked);

    raw_actif = activer;
}



int unix_text_kbhit(void)
{
    struct timeval tv = { 0, 0 };
    fd_set readfds;

    FD_ZERO(&readfds);
    FD_SET(STDIN_FILENO, &readfds);

    return select(STDIN_FILENO + 1, &readfds, NULL, NULL, &tv) == 1;
}




int main()
{


int res, top=0;
int activer=1;

mode_raw(activer);


    while (res!='q'){
       if (unix_text_kbhit()){
        res=getchar();
        printf("touche %c pressee, val ascii : %d\n",res,res);
       }
       if(clock()>top+1000){  // contrôler le temps
          top=clock();
          putchar('0');
       }
    }

mode_raw(!activer);

    return 0;
}
 

aragats

Daemon

Reaction score: 470
Messages: 1,130

In your program putchar() perfectly works here.
Another thing is that you should not assign output of clock() to an int.
 
OP
OP
Fabien

Fabien

Member

Reaction score: 4
Messages: 28

Tkank you for helping.

The thing is when I run the program in FreBSD, using geany, everythings works but putchar(), no '0' is printed.
The code is from a book, I just copy/paste the main function, so I don't know anything about clock()'s output, I'll do some research right now, thank you.
 
OP
OP
Fabien

Fabien

Member

Reaction score: 4
Messages: 28

In here, clock() slow down the program, so we have time to see what is going on.

Do you mean "while (res!='q')" doesn't work. It works for me, when I press "q", the program exit the loop and stop.
 
OP
OP
Fabien

Fabien

Member

Reaction score: 4
Messages: 28

Ok, sorry, i understand what you meant. I neither a native english or C speaker, so I am having a "hard" time to figure what's happening...

I removed clock() and putchar() works, i guess your are not surprised....

The question is why the code works on Linux and not on FreeBSD (I am not reproaching anything to the OS!).

I am having so much fun. I'll continue this tomorrow.
Thank you aragats.
 

obsigna

Aspiring Daemon

Reaction score: 519
Messages: 894

aragats, on FreeBSD, clock_t is actually int, so technically it is not an error to assign the output of clock() to an int variable, perhaps it maybe considered bad style, but this does not make up for the actual failure.

Fabien, on FreeBSD clock() measures the time in CLOCKS_PER_SEC, the value of which is 128. The condition if (clock()>top+1000) is true the first time after roughly 8 seconds and then every 8 seconds once again, which for hasty people is quite a long delay, and those might have quit the process already until putchar() would have been triggered the first time. I suggest to replace the value 1000 by CLOCKS_PER_SEC, and putchar() would be triggered every 1 second.

Anyway, the real culprit is that FreeBSD does buffered writing even into stdout, and this means, you need to add the function call fflush(stdout); after each putchar() in order to flush the buffer and get the 0’s written to the console.
 

aragats

Daemon

Reaction score: 470
Messages: 1,130

on FreeBSD, clock_t is actually int
It depends on platform, see /usr/include/x86/_types.h:
Code:
  74 #ifdef  __LP64__
  75 typedef __int32_t   __clock_t;      /* clock()... */
  76 typedef __int64_t   __critical_t;
  77 #ifndef _STANDALONE
  78 typedef double      __double_t;
  79 typedef float       __float_t;
  80 #endif
  81 typedef __int64_t   __intfptr_t;
  82 typedef __int64_t   __intptr_t;
  83 #else
  84 typedef unsigned long   __clock_t;
  85 typedef __int32_t   __critical_t;
  86 #ifndef _STANDALONE
  87 typedef long double __double_t;
  88 typedef long double __float_t;
  89 #endif
  90 typedef __int32_t   __intfptr_t;
  91 typedef __int32_t   __intptr_t;
  92 #endif
 

obsigna

Aspiring Daemon

Reaction score: 519
Messages: 894

I consulted the very same file, and FreeBSD x86_64 is a LP64 system, so clock_t is int. If you don’t believe it, then verify it with the following:
Code:
#include <stdio.h>
#include <time.h>

int main(int argc, const char *argv[])
{
   printf("%zd\n", sizeof(clock_t));
   return 0;
}
On two of my 12.0-RELEASE x86_64 machines this gives 4 = sizeof(int32_t).

PS: If you compile the above snippet with the -E flag, then you’d see, that the pre-processor resolves __clock_t to __int32_t.
Code:
...
# 49 "/usr/include/x86/_types.h" 2 3 4

typedef signed char __int8_t;
typedef unsigned char __uint8_t;
typedef short __int16_t;
typedef unsigned short __uint16_t;
typedef int __int32_t;
typedef unsigned int __uint32_t;

typedef long __int64_t;
typedef unsigned long __uint64_t;
# 75 "/usr/include/x86/_types.h" 3 4
typedef __int32_t __clock_t;
typedef __int64_t __critical_t;

typedef double __double_t;
typedef float __float_t;

typedef __int64_t __intfptr_t;
typedef __int64_t __intptr_t;
# 93 "/usr/include/x86/_types.h" 3 4
...
 

aragats

Daemon

Reaction score: 470
Messages: 1,130

obsigna , I didn't tell you're wrong, it is int32 on amd64.
Personally I have FreeBSD on other platforms too, so to be on the safe side I'd use unsigned long as a cast for clock_t.
 
OP
OP
Fabien

Fabien

Member

Reaction score: 4
Messages: 28

Merci obsigna!

It works but its very slow, I am trying to speed up the priting, but I fail. Removing clock() works.
I have to read more about CLOCKS_PER_SEC.

Thank you!
 
OP
OP
Fabien

Fabien

Member

Reaction score: 4
Messages: 28

The first code with kbhit implementation works as expected: putchar() is triggered every 1 second.
But I rewrite the code using ncurses, and that is what make him slow. I had to write CLOCKS_PER_SEC/10000 or so.
Does anyone know why clock() act differently with ncurses. What am I doing wrong?
I don't think changing the value of CLOCKS_PER_SEC in /usr/include/time.h is a solution


Code:
#include <time.h>
#include <stdio.h>
#include <ncurses.h>

int main()
{

int ch;

float top=0;

    initscr();
    keypad(stdscr,TRUE);
    timeout(TRUE);
    noecho();
    
    while (ch!='q'){       
       if ((ch=getch())){
            if(ch>1){
            printw(" Touche %c pressee, val ascii : %d" ,ch,ch);
            }
       }
       if(clock()>top+CLOCKS_PER_SEC/10000){                                 
               top=clock();
            putchar('0');
            fflush(stdout);
       }
    }

    endwin();


return 0;

}
 
Top