为什么/如何编译?

时间:2009-10-07 08:44:42

标签: c++ visual-studio

MS Visual Studio 2008中的C ++。警告级别4加上一系列额外警告也已启用。我希望这会发出警告 至少 ,但更可能是编译错误?

功能声明如下:

int printfLikeFunction(
   const int               bufferLength,
   char * const            buffer,
   const char * const      format,
   ... );

代码用法 - 有一个错字:虽然传入了outputBuffer的ARRAY_SIZE,但outputBuffer本身并不是 - 当然这不应该编译:

printfLikeFunction( ARRAY_SIZE( outputBuffer ), "Format: %s, %s", arg1, arg2 );

显然这是错误的并且已经犯了错误。但是编译器应该抓住它! buffer参数应该是一个char指针,并且它正在传递一个字符串文字,这是一个const char-pointer。这一定是个错误。 (arg1和arg2也是(可能是const)char指针,所以巧合的是声明匹配,即使没有outputBuffer在正确的位置)。

在运行时,此代码在尝试写入字符串文字时崩溃。毫不奇怪,我只是不明白它是如何被允许编译的。

(顺便说一下,这可能就是为什么sprintf_s的缓冲区和大小参数与此函数的顺序不同 - 它会使这些错误明确失败)。

4 个答案:

答案 0 :(得分:9)

C ++对字符串文字有一个特殊的漏洞,可以与前const C风格的代码兼容。尽管字符串文字是const char的数组,但它们可以转换为指向非const字符的指针。

释义4.2 / 2 [conv.array]:'narrow'字符串文字可以转换为非const char的指针类型的右值。仅当存在显式目标类型(例如函数参数)时才考虑转换,而不需要在需要进行右值转换的一般左值时进行转换。

此转换已弃用,但仍可用。请注意,虽然转换允许将文字转换为指向非const char类型的指针,但它仍会调用未定义的行为以尝试通过此指针修改字符串文字中的任何字符。

答案 1 :(得分:2)

我似乎记得编译器有一个控制字符串文字处理方式的选项。默认情况下,它们被视为char *,以便不会破坏大量现有的非常量安全代码,但您可以将其更改为将其视为const char *。这可能有助于触发您正在寻找的错误。

(稍后)我目前没有微软的编译器,但是在MSDN上查看引用我似乎无法找到这样的选项。我可能会考虑GCC,它确实有这样的选择。

答案 2 :(得分:1)

int printfLikeFunction(    const int bufferLength,    char * const buffer,    const char * const格式,    ......);

缓冲区参数指定为char * const,因此它只保护要修改的缓冲区地址,而不是缓冲区内容。

为了避免写入缓冲区,需要将其声明为const char * const格式。

编译器允许写入缓冲区,因为您将其声明为char *。 const后缀修饰符仅阻止在函数中重新分配缓冲区值。

请参阅http://jriddell.org/const-in-cpp.html以查看const修饰符对变量的影响

答案 3 :(得分:1)

C中的字符串文字是const char指针(char*const),而不是const chars(const char* const)的常量指针。

C ++最初遵循C用法,但随后在某些时候修改了ANSI C ++标准(我不确定何时),使它们成为const char* const。传统上,Microsoft产品往往倾向于重视与先前版本的兼容性而不是合规性 - 可能存在强制“新”行为的编译器选项,但由于MSDN上的字符串文字的示例都是非const的,我怀疑是否存在。