编辑:如果我们有这个
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, ... );
答案 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)的版本以及所用的编译器选项,上述调用不会产生预期的结果。