从宏块

时间:2015-09-18 18:35:07

标签: c++ variables macros

我正在尝试根据操作系统编写一个行为不同的函数。

我在我的函数中得到了这段代码:

#ifdef OS_WINDOWS
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    int cols;
    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
    cols = csbi.srWindow.Right - csbi.srWindow.Left + 1;
    #else
        int cols;
        #ifdef TIOCGSIZE
        struct ttysize ts;
        ioctl(STDIN_FILENO, TIOCGSIZE, &ts);
        cols = ts.ts_cols;
        #elif defined(TIOCGWINSZ)
        struct winsize ts;
        ioctl(STDIN_FILENO, TIOCGWINSZ, &ts);
        cols = ts.ws_col;
        #endif // TIOCGSIZE
    #endif // OS_WINDOWS

所以,我想获得列数,但是需要以两种不同的方式为Windows和Linux完成...然后我想继续使用cols变量。但我得到variable 'cols' is uninitialized when used here

如何从宏块中“提取”cols变量?

2 个答案:

答案 0 :(得分:2)

编译器在Windows上看到的内容

CONSOLE_SCREEN_BUFFER_INFO csbi;
int cols; //This is the only place where `cols` is delcared!
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
cols = csbi.srWindow.Right - csbi.srWindow.Left + 1;

编译器在Windows上看到的不是

    struct ttysize ts;
    ioctl(STDIN_FILENO, TIOCGSIZE, &ts);
    cols = ts.ts_cols; //cols is not declared

    struct winsize ts;
    ioctl(STDIN_FILENO, TIOCGWINSZ, &ts);
    cols = ts.ws_col; //cols is not declared

请注意,非Windows代码中没有cols声明

一个简单的解决方案是在宏块之前移动cols的decalration。

int cols = 0; //or -1 or some other error value
#ifdef OS_WINDOWS
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
//...

作为预处理器宏的注释: 预编译器在代码编译之前运行,处理#include#define(替换文本),#ifdef(有条件地包括代码块),依此类推。编辑器和IDE可能会显示灰色的非使用块,但您也可以单独查看预处理器输出(编译器标志取决于您的编译器),这可以帮助您找到导致错误的原因。

答案 1 :(得分:1)

当处理特定于操作系统的行为时,您会注意到当这些条件代码与其他非条件代码“内联”时,代码很复杂且难以理解或维护。

使这种更清洁和更清晰的一种方法是将条件代码放在函数之外,并在明确分离的函数中选择其他选项。

例如,假设概念是获取列。知道每种操作系统情况都不同,首先声明一个函数来获取列:

int GetColumns();

现在,根据操作系统定义函数:

#ifdef OS_WINDOWS

int GetColumns()
{
 int cols(0);
 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
 cols = csbi.srWindow.Right - csbi.srWindow.Left + 1;

 return cols;
}

#else
#ifdef TIOCGSIZE
int GetColumns()
{
  int cols;
  struct ttysize ts;
  ioctl(STDIN_FILENO, TIOCGSIZE, &ts);
  cols = ts.ts_cols;
  return cols;
}
#elif defined( TIOCGWINSZ )
int GetColumns()
{
  int cols;
  struct winsize ts;
  ioctl(STDIN_FILENO, TIOCGWINSZ, &ts);
  cols = ts.ws_col;
  return cols;
}
#endif // elif

#endif // else to OS_WINDOWS

我没有审查这些块中的所有代码,但这里的重点是将这些概念分开,以使代码更清晰,更清晰,更易于使用。

在您的主要功能中,您现在只需要:

int cols = GetColumns();

这样做是承认你需要一种获取列的方法,就是这样。它清楚地区分了从要求它的代码中获取列的复杂性。

现在,各种条件代码的副作用不再破坏您正在编写的功能。如果有并发症,它们现在与各种版本的GetColumns的主体隔离。该函数“包装”局部变量的问题,函数调用的差异,函数内部。

这也使得它可以在程序的其他地方使用,而无需重复条件代码。