与sprintf(snprintf)重叠的内存

时间:2018-10-26 22:24:39

标签: c++ printf language-lawyer undefined-behavior

编辑:如果我们有这个

char value_arr[8];    
// value_arr is set to some value
snprintf(value_arr, 8, "%d", *value_arr);

此行为是否已定义?


让我说说我出于某些不合理的原因

char value_arr[8];
// value_arr is set to some value
int* value_i = reinterpret_cast<int*>(value_arr);

snprintf(value_arr, 8, "%d", *value_i); // the behaviour in question

是否可以保证,例如,如果*value_i = 7,则value_arr将采用“ 7”的值。是否定义了此行为?这样value_i首先被取消引用,然后按值传递,然后格式化,然后存储到数组中。

通常,*value_i的值不会发生变化,但是将字符串存储到value_arr会违反此规定。

当我测试它时,它似乎可以按预期的方式运行,但是在文档中似乎找不到明确的答案。函数签名具有...,据我所知与va_list有关,但是恐怕我对可变函数的工作不是很了解。

int sprintf (char* str, const char* format, ... );

3 个答案:

答案 0 :(得分:3)

对于原始代码,评估表达式*value_i会违反严格的别名规则,从而导致未定义的行为。不允许将char数组别名为int

对于已编辑的代码snprintf(value_arr, 8, "%d", *value_arr);,这很好,它将格式化数组中第一个字符的字符代码。在进入函数之前,对函数自变量的求值是有序的。 (C ++ 17 intro.execution / 11)

答案 1 :(得分:1)

这是不确定的行为;与int*相比,您可以使用类型为char[8]的指针指向类型为int*的对象,该对象具有不同的/宽松的对齐要求。取消引用该指针后将产生UB。

答案 2 :(得分:1)

可以在https://en.cppreference.com/w/cpp/io/c/fprintf中找到以下内容:

  

如果调用sprintf或snprintf导致在重叠的对象之间进行复制,则该行为是不确定的。

根据此页面,我将解释您的示例属于这种情况,因此将其归类为“未定义的行为”。

编辑:更多详细信息,位于https://linux.die.net/man/3/snprintf

  

某些程序不恰当地依赖于以下代码

     

sprintf(buf,“%s一些进一步的文本”,buf);

     

将文本附加到buf。但是,标准明确指出,如果在调用sprintf(),snprintf(),vsprintf()和vsnprintf()时源缓冲区和目标缓冲区重叠,则结果不确定。根据所用gcc(1)的版本以及所用的编译器选项,上述调用不会产生预期的结果。