如何高效地将波特率从int类型转换为speed_t类型?

6

函数cfsetospeedcfsetispeed采用波特率类型speed_t

int cfsetispeed(struct termios *termios_p, speed_t speed);
int cfsetospeed(struct termios *termios_p, speed_t speed);

类型 speed_t 基本上是一个整数,但强制转换不是解决方案,这可以从 termios.h 中的波特率定义中看出。
#define B0  0x00000000
#define B50 0x00000001
#define B75 0x00000002
// ...
#define B9600   0x0000000d
#define B19200  0x0000000e
#define B38400  0x0000000f

当我处理用户输入(例如来自文件的输入)时,我会将字符串“9600”转换为整数9600,然后转换为B9600。我基本上正在寻找一种通用的方法来进行以下转换:
// 0 -> B0
// 50 -> B50
// 75 -> B75
// ...
// 9600 -> B9600 
// 19200 -> B19200
// 38400 -> B38400

一种int(例如9600)转换为speed_t(例如B9600)的方法是使用switch-case结构。是否有更好的方法来实现这个目标?


1
switch-case结构似乎是一个不错的解决方案...也许可以封装在一个转换函数speed_t baudrate(int br) { ... }中,然后使用cfsetispeed(term, baudrate(19200));或类似的代码,你的代码看起来相当优雅。 - Ctx
1
常量查找表? - Martin James
1
那些BXXX的东西真的应该是一个枚举。 - Martin James
@MichaelWalz 我问的是 int -> size_t,不是相反的。 - Sparkler
查找表并不实用,因为大部分数组元素会是空白的:lookup[50] = B50,等等。 - Sparkler
不要使用 int 来保存波特率的值,除非你确定你的代码将在所有平台上运行时都有足够大的 int。此外,波特率不能为负数。更好的选择是 uint_fast32_tuint_least32_tunsigned longuint32_t(当你确定这种类型存在时,几乎到处都是这种情况)。 - 12431234123412341234123
2个回答

8

我发现需要这个。将switch case语句粘贴在这里供您复制。

int get_baud(int baud)
{
    switch (baud) {
    case 9600:
        return B9600;
    case 19200:
        return B19200;
    case 38400:
        return B38400;
    case 57600:
        return B57600;
    case 115200:
        return B115200;
    case 230400:
        return B230400;
    case 460800:
        return B460800;
    case 500000:
        return B500000;
    case 576000:
        return B576000;
    case 921600:
        return B921600;
    case 1000000:
        return B1000000;
    case 1152000:
        return B1152000;
    case 1500000:
        return B1500000;
    case 2000000:
        return B2000000;
    case 2500000:
        return B2500000;
    case 3000000:
        return B3000000;
    case 3500000:
        return B3500000;
    case 4000000:
        return B4000000;
    default: 
        return -1;
    }
}

2
请注意,在Linux中,speed_t是无符号的,因此返回-1可能不是您想要的。请参见https://code.woboq.org/userspace/glibc/sysdeps/unix/sysv/linux/bits/termios.h.html。 - Danny
1
我刚刚发现一个库使用了-1并在编译器中抛出了有符号警告。那么B0会更好吗?termios.h定义了它。零波特是否存在,或者这与-1的意图一样好? - tresf
使用 int 而不是 speed_t,使用负值和不一致的缩进风格会得到 -1 的评分。此外,int 无法容纳 38400 或任何更大的值。最好使用类似于 uint_fast32_tunsigned long 的数据类型。 - 12431234123412341234123
1
节省了很多时间。谢谢。 - Rahul Das

4
您需要一个查找表,但不是一个简单粗暴的表:
#include <stdio.h>    
#include <termios.h>       

struct
{
  int rawrate;
  int termiosrate;
} conversiontable[] =
{
  {0, B0},
  {50, B50},
  {75, B75},
  // you need to complete the table with B110 to B38400
};

int convertbaudrate(int rawrate)
{
  for (int i = 0; i < sizeof(conversiontable) / sizeof(conversiontable[0]); i++)
  {
    if (conversiontable[i].rawrate == rawrate)
    {
      return conversiontable[i].termiosrate;
    }
  }

  return -1;    // invalid baud rate
}

int main()
{
  printf("%d -> %d\n", 50, convertbaudrate(50));
  printf("%d -> %d\n", 75, convertbaudrate(75));
}

那应该可以自解释。如果不行,请评论。

我确实更喜欢使用switch/case,编译器可以更好地进行优化。 - Karim
@Karim 可能是对的,但除非 convertbaudrate 被频繁调用,否则可能没有必要进行优化,而这很可能不是情况。 - Jabberwocky
@Karim 警惕过早优化。 - Jabberwocky
3
现在这条评论不公平,用一个switch/case语句简化代码并让编译器做优化,正是避免过早优化的最佳实践。 - Karim
1
@Karim,不太确定你是否理解我的观点,请谷歌“过早优化”。 - Jabberwocky
4
“过早优化”是一个术语,用于描述程序员在设计代码时过分考虑性能问题的情况。这可能导致设计不够优雅或代码错误,因为程序员在优化代码时分心了,从而使代码变得复杂。您的误解在于认为应该保持代码简洁清晰,并让编译器来进行优化。这与“过早优化”恰恰相反。 - Karim

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