我正在尝试根据操作系统编写一个行为不同的函数。
我在我的函数中得到了这段代码:
#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变量?
答案 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的主体隔离。该函数“包装”局部变量的问题,函数调用的差异,函数内部。
这也使得它可以在程序的其他地方使用,而无需重复条件代码。