我一直在尝试打印一个字符串文字但似乎我做错了,因为我收到了编译警告。这可能是由于错误的格式化或我对c_str()
函数的误解,我认为这应该返回string
。
parser.y: In function ‘void setVal(int)’:
parser.y:617:41: warning: format not a string literal and no format arguments [-Wformat-security]
第617行:
sprintf(temp, constStack.top().c_str());
有这些声明
#include <stack>
const int LENGTH = 15;
char *temp = new char[LENGTH];
stack<string> constStack;
如何为字符串提供正确的格式化?
答案 0 :(得分:9)
简单 - 提供格式字符串:
sprintf(temp, "%s", constStack.top().c_str());
但更好,更好:
string temp = constStack.top();
答案 1 :(得分:4)
您在评论中告诉我,问题不在于您的代码没有达到预期效果的警告。
解决这个和其他类似问题的方法是摆脱C ++代码中强大的C影响。具体来说,不要使用原始动态分配的char数组或sprintf
。请改用std::string
。
在这种情况下,您使用sprintf
非常错误。你见过它的签名吗?它是这样的:
sprintf(char *str, char const *format, ...)
str
是操作的输出。 format
描述输出应该是什么。其余的是格式参数,它必须通过纯约定匹配format
中描述的内容。
现在这个“休息”写成...
,意味着你可以传递任意数量的参数,甚至是零。这就是为什么你的代码甚至可以编译(顺便提供一个很好的例子,说明为什么...
是一个危险的特性)。
在您的代码中,输出字符串可能不正确,是您的temp
字符串。描述输出的格式几乎肯定是错误的,它会发生在你的堆栈顶部。
这只是将一个字符串分配给另一个字符串,使用sprintf
只是因为它或多或少可以作为其功能集提供的特殊情况吗?没有必要进行这样的黑客攻击,因为C ++的std::string
开箱即用了字符串:
std::string temp = constStack.top();
请注意,这也消除了提前知道字符串长度的需要。
如果由于某种原因,您确实需要格式化(但您的问题并不真正显示它需要),那么请详细了解字符串流作为格式化字符串的替代解决方案。< / p>
答案 2 :(得分:3)
警告表明它是-Wformat-security
选项的结果;你可以通过删除选项来禁用警告;但这可能是不明智的。
除非您的代码要广泛分发,否则security issue可能是理论上的。或许更直接的问题是代码崩溃或异常行为的可能性。
问题是字符串是可变的,并且可能在运行时包含格式化字符,导致它尝试读取不存在的参数。例如,如果从用户输入接收到字符串并且用户输入“%s”,则它将尝试从堆栈上的某个位置读取字符串。这最多会在temp
中放置垃圾,但更糟糕的是如果内存读取在前15个字节中没有包含空字符,则会超出临时值并损坏堆(在本例中)。堆损坏可能比堆栈损坏更糟糕 - 潜伏的bug在你的代码中很长时间没有引起注意,只是在经过一些无关的更改后才开始崩溃;如果它确实崩溃了,它就不可能与原因有任何关系。