C++ terminfo参数化字符串%d编码行为
我试图理解terminfo的参数化字符串解析器中C++ terminfo参数化字符串%d编码行为,c++,c,ncurses,curses,terminfo,C++,C,Ncurses,Curses,Terminfo,我试图理解terminfo的参数化字符串解析器中%d编码的行为。相关手册页为,并说明- %[[:]flags][width[.precision]][doxXs] as in printf, flags are [-+#] and space. Use a ":" to allow the next character to be a "-" flag, avoiding interpreting "%-" as an operator.
%d
编码的行为。相关手册页为,并说明-
%[[:]flags][width[.precision]][doxXs]
as in printf, flags are [-+#] and space. Use a ":" to allow the
next character to be a "-" flag, avoiding interpreting "%-" as an
operator.
但没有说明从何处打印值以及如何处理边缘案例。它们是来自堆栈还是来自传递给参数化字符串的参数?另外,当传递额外的参数(参数化字符串中的非相等%d
)或存在额外的%d
(参数化字符串不正确)时会发生什么情况?那个未定义的行为或实现是由定义定义的还是由定义定义的
我试图通过手动写入一些有效和无效字符串并验证输出来检查一些情况,但到目前为止,所有内容都有点不一致,因此我无法在这里看到模式-
#include <iostream>
#include <curses.h>
#include <term.h>
using namespace std;
int main() {
// single %d prints single argument
// => 2
auto res = tparm("[%d]", 2);
cout << res << endl;
// single %d prints single argument and ignores additional
// => 2
res = tparm("[%d]", 2, 3, 4);
cout << res << endl;
// multiple %d prints 0 for absent additional arguments
// => 2-0-0-0
res = tparm("[%d-%d-%d-%d]", 2);
cout << res << endl;
// multiple %d prints with equal number of arguments prints
// first two correctly and rest 0
// => 2-3-0-0-0
res = tparm("[%d-%d-%d-%d-%d]", 2,3,4,5,6);
cout << res << endl;
// single value pushed to stack prints from stack
// => 2
res = tparm("[%p1%d]", 2);
cout << res << endl;
// single value pushed to stack prints from stack and ignores extra arguments
// => 2
res = tparm("[%p1%d]", 2,3,4);
cout << res << endl;
// single value pushed to stack prints from stack and additional prints are 0
// if no arguments are provided
// => 2-0-0
res = tparm("[%p1%d-%d-%d]", 2);
cout << res << endl;
// single value pushed to stack prints from stack and additional prints 0
// even if equal arguments are provided
// => 2-0-0
res = tparm("[%p1%d-%d-%d]", 2,3,4);
cout << res << endl;
// single value pushed to stack prints from stack after pop()?
// => 100-<garbage>
res = tparm("[%p1%d-%c]", 100);
cout << res << endl;
// pushed to stack via {} and equal arguments provided, prints all
// => 2-1-100-200
res = tparm("[%{1}%{2}%d-%d-%d-%d]", 100, 200);
cout << res << endl;
// pushed to stack via {} and %p1 equal arguments provided
// prints only stack and rest 0
// => 100-2-1-0
res = tparm("[%{1}%{2}%p1%d-%d-%d-%d]", 100, 200);
cout << res << endl;
}
#包括
#包括
#包括
使用名称空间std;
int main(){
//单个%d打印单个参数
// => 2
自动恢复=tparm(“[%d]”,2);
cout在您的示例中注意到的一个问题是它们使用未定义的行为。terminfo的已定义的行为使用显式参数标记(如%p1
)将推送参数传递到堆栈上,在堆栈中它们可以由操作符(如%d
)弹出。如果没有这些,您就依赖于ncurses的解决方法s表示termcap(它没有参数标记),这将使表达式
res = tparm("[%d-%d-%d-%d]", 2);
尝试从参数列表中读取多个参数。您的示例给出了一个,因此您处于C语言未定义行为的领域(即,可变长度参数列表中的参数数量错误)。如果调用传递了额外参数,可能可以(例如,请参阅),但使用更少的内存,结果可能是访问参数列表之外的内存
对评论作出答复:
ncurses允许在不使用%p1
的情况下使用termcap样式的%d
。但它会计算参数的数量,并在进行实际替换之前列出这些参数。由于它将这些参数作为变长参数列表进行处理,因此无法确定应用程序是否为给定字符串传递了错误数量的参数
进一步阅读:
- ,例如:
/*
*分析字符串以查看我们需要从varargs列表中获取多少参数,
*以及它们的类型。我们只接受字符串参数,如果
*在显式参数引用后显示为%l或%s格式(例如。,
*%p2%s)。所有其他参数都是数字。
*
*“number”粗略计算我们在字符串中看到的pop的数量,并且
*“popcount”显示字符串中的最高参数号。我们希望
*只需使用后一个计数,但如果我们正在读取termcap字符串,则
*在某些情况下,我们可能无法看到显式参数编号。
*/
以及TimPCAP缺少参数令牌的特征。< /P>是C还是C++?“未定义行为”和“实现定义行为”有什么区别?@ ScottHunter不重要,因为两个Langs都可以使用TPARM()。.我之所以编写未定义的行为,是因为我在某些param..strings组合的ncurses上遇到分段错误,但当我在其他实现(其他语言的另一个lib)上尝试相同的操作时,它给出了完全不同的结果(因此可能是错误的,或者是使其成为实现定义的行为)。
/*
* Analyze the string to see how many parameters we need from the varargs list,
* and what their types are. We will only accept string parameters if they
* appear as a %l or %s format following an explicit parameter reference (e.g.,
* %p2%s). All other parameters are numbers.
*
* 'number' counts coarsely the number of pop's we see in the string, and
* 'popcount' shows the highest parameter number in the string. We would like
* to simply use the latter count, but if we are reading termcap strings, there
* may be cases that we cannot see the explicit parameter numbers.
*/