fread() 和 read() 得到不同的数据

问题描述 投票:0回答:1

我有一个检测键盘的程序。

起初,我用

read()
从键盘设备读取
struct input_event
,效果很好。

然后我尝试用

read()
替换
fread()
。它得到了错误的数据。

演示如下。要重现错误,您需要与您的键盘开发人员交换

/dev/input/event0
并使用
sudo
运行它。

#include <unistd.h>
#include <stdio.h>
#include <sys/fcntl.h>
#include <linux/input.h>
#include <stdlib.h>

#define USE_FREAD

static void check_keyboard (int fd)
{
    static struct input_event event;
    
#ifdef USE_READ
    {
        //use read(). it works well.
        if (read (fd, &event, sizeof (event)) == -1)
            perror ("read()"), exit (EXIT_FAILURE);
    }
    
#else
#ifdef USE_FREAD
    {
        //use fread(). it gets wrong data
        int cloned = dup (fd);
        if (cloned == -1)
            perror ("dup()"), exit (EXIT_FAILURE);
    
        FILE *file = fdopen (cloned, "r");
        if (file == NULL)
            perror ("fdopen()"), exit (EXIT_FAILURE);
    
        if (fread (&event, sizeof (event), 1, file) != 1) {
            if (feof (file))
                fprintf (stderr, "waring: fread() get EOF");
            else if (ferror (file))
                fprintf (stderr, "fread() failed\n"), exit (EXIT_FAILURE);
        }
    
        fclose (file);
        puts ("fread() over");
    }
#endif
#endif
    
    if (event.type != EV_KEY)
        return;
    switch (event.value) {
        case 0:
            puts ("key released");
            break;
        case 1:
            printf ("key pressed, code:%d\n", event.code);
            break;
        case 2:
            puts ("repeat automatically");
            break;
    }
}

int main()
{
    int fd = open ("/dev/input/event0", O_RDONLY);
    if (fd == -1)
        perror ("open()"), exit (EXIT_FAILURE);
        
    for (; ;) {
        check_keyboard (fd);
    }
    
    close (fd);
}

如果定义了

USE_READ
,它可以检测键盘事件。如果定义了
USE_FREAD
,它只会打印“fread() over”。

我试着用gdb来观察

event
的值。但是还有许多其他事件混淆了数据。

我的环境:debian 12, gcc 12.2.0 , kernel 6.1.0-7-amd64 .

c linux fread
1个回答
0
投票

我已经按照评论中的建议解决了

只需使用

setvbuf()
禁用缓冲区:

#ifdef USE_FREAD
    {
        //use fread(). it gets right data now.
        int cloned = dup (fd);
        if (cloned == -1)
            perror ("dup()"), exit (EXIT_FAILURE);
    
        FILE *file = fdopen (cloned, "r");
        if (setvbuf (file, NULL, _IONBF, 0) != 0)
            perror ("setvbuf()"), exit (EXIT_FAILURE);
    
        if (fread (&event, sizeof (event), 1, file) != 1) {
            if (feof (file))
                fprintf (stderr, "waring: fread() get EOF");
            else if (ferror (file))
                fprintf (stderr, "fread() failed\n"), exit (EXIT_FAILURE);
        }
    
        fclose (file);
    }
#endif

顺便检查一下返回值。

© www.soinside.com 2019 - 2024. All rights reserved.