在同一个项目中包含<termios.h>和<asm/termios.h>

6
我希望实现的目标是:我想为一些类似于tty*UART映射终端设置自定义波特率值。
操作方法: 到目前为止,我找到的唯一方法是使用位于<asm/termios>头文件中的struct termios2结构体(如此处所述,第一个答案)。
我的解决方案到目前为止非常有效,但现在我需要使用一些函数:
speed_t cfgetispeed(const struct termios *);
int     tcdrain(int);
int     tcflow(int, int);
int     tcflush(int, int);
int     tcgetattr(int, struct termios *);
pid_t   tcgetsid(int);
int     tcsendbreak(int, int);
int     tcsetattr(int, int, struct termios *);

问题在于 <asm/termios.h> 中没有这些函数,而我需要包含 <termios.h> 才能使用它们。

问题:如果我同时包含这两个头文件 (<asm/termios.h><termios.h>),编译器会报告函数和结构体重复声明的错误,这是正确的。
如何解决这个问题,而不使用一些晦涩难懂的做法(比如像 这里 提到的将其中一个头文件放入命名空间)?

同一作者的相关问题:http://stackoverflow.com/questions/37697155/使用两个具有相同函数名称的头文件 - Patrick Trentin
1
你可以采取以下措施:1)将头文件包装在它们自己的命名空间中,2)重构你的代码,使得没有翻译单元包含两者,3)通过代理头文件包含 <asm/termios.h> ,并用宏隐藏冲突的定义。其中(2)是最困难的。 (3)至少和(1)一样“晦涩难懂”,而且也是一个技巧。 - Mike Kinghan
4个回答

6

如何在不使用一些晦涩的做法(比如将其中一个标题包含在命名空间中,就像这里提到的那样)的情况下解决这个问题?

如果你认为命名空间很晦涩,我不知道你会怎么称呼这个:

#define termios asmtermios
#include <asm/termios.h>
#undef  termios
#include <termios.h>

无论如何,这也可以让你摆脱error: redefinition of 'struct termios'错误。

1
我会称之为一个解决方案! :) - JakeSays

2
我遇到了类似的问题——希望使用像termios2TCGETS2BOTHER这样的定义来支持自定义波特率,同时仍然使用传统的termios调用。我本能地将termios2相关内容包装在它自己的编译单元中,并且没有遇到任何问题。所以我的结构看起来像这样:

serial_driver.c/.h

"Original Answer"翻译成"最初的回答"
#include <termios.h>
#include <fcntl.h>
#include <dirent.h>

int open_port(int fd, int baudrate, eParitySetting parity, int numStopBits)
{
  if(baudrate_is_non_standard(baudrate)
    setNonStandardBaudRateTermios(fd, baudrate, parity, numStopBits);
  else
    //all the normal tcgetattr/cfsetospeed/tcsetattr
}

int do_other_things(void)
{
  //all the normal tcsendbreak/tcflush/etc things
}

serial_driver_abr.c/.h

#include <asm/termios.h> /* asm gives us the all important BOTHER and TCGETS2 */
#include <fcntl.h>
#include <dirent.h>
#include <stropts.h> /* Oddly, for ioctl, because ioctl.h causes include dramas */

setNonStandardBaudRateTermios(int fd, int baudrate, eParitySetting parity, int numStopBits)
{
  //All the termios2/ioctl/TCGETS2/BOTHER things
}

对我而言,它运行良好。


0

我认为这些答案都没有正确地解决问题(它们相当繁琐)。glibc的源代码可以让你很容易地实现这些函数:

例如,tcdrain只是一个简单的ioctl调用:

ioctl (fd, TCSBRK, 1)

0

我遇到了与旧的 ARM 交叉编译器相同的问题,但是发现最新的编译器 gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf 使用不同的头文件解决了这个问题。以下是我的代码:

[uart_config.c]
#include <asm/termbits.h>
#include <sys/ioctl.h>

/* functions */
int uart_config_baudrate(int fd)
{
    struct termios2 tio;

    ioctl(fd, TCGETS2, &tio);
    tio.c_cflag &= ~CBAUD;
    tio.c_cflag |= BOTHER;
    tio.c_ispeed = MY_SPECIAL_BAUDRATE_NUMBER;
    tio.c_ospeed = MY_SPECIAL_BAUDRATE_NUMBER;
    return ioctl(fd, TCSETS2, &tio);
}

[main.c]
static int init_uart(void)
{
    struct termios tp;
    int rc;

    memset(&tp, 0, sizeof(tp));
    tp.c_cflag = MY_SPECIAL_BAUDRATE | CS8 | CLOCAL | CREAD | PARENB | PARODD;
    tp.c_iflag = IGNPAR;
    tp.c_oflag = 0;

    tp.c_lflag = 0;     /* set input mode to non-canonical */

    tp.c_cc[VTIME] = 0; /* inter-character timer unused */
    tp.c_cc[VMIN] = 1;  /* blocking read until 5 chars received */

    tcflush(fd, TCIFLUSH);
    rc = tcsetattr(fd, TCSANOW, &tp);

    return rc;
}

int main()
{
    int fd;

    fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY);
    init_uart(fd);  // add your error handling
    uart_config_baudrate(fd); // add your error handling
    ...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接