C++ 这是DWORD相关代码未定义的行为吗?
这是我第三次试图澄清我对这个话题的困惑。但这次我有不同的问题 我有这个密码C++ 这是DWORD相关代码未定义的行为吗?,c++,undefined-behavior,C++,Undefined Behavior,这是我第三次试图澄清我对这个话题的困惑。但这次我有不同的问题 我有这个密码 DWORD v1, v2, v3, Build; GetVersion(&v1, &v2, &v3, &Build); sprintf(VersionStr, "%d.%d.%d.%d", v1, v2, v3, Build); 这是10年前用VisualStudio写的。我知道DWORD总是无符号的,这是真的吗 现在,其中一个答案引用了标准的某个版本(这个标准版本适用于我的
DWORD v1, v2, v3, Build;
GetVersion(&v1, &v2, &v3, &Build);
sprintf(VersionStr, "%d.%d.%d.%d", v1, v2, v3, Build);
这是10年前用VisualStudio写的。我知道DWORD总是无符号的,这是真的吗
现在,其中一个答案引用了标准的某个版本(这个标准版本适用于我的代码吗?),其中提到了va_arg
:
在这一点上,标准并非100%明确。一方面,你得到了
va_arg规范,其中说明(§7.15.1.1/2):
如果没有实际的下一个参数,或者如果类型与
实际下一个参数的类型(根据
默认参数),该行为未定义,但
下列情况:
一种类型是有符号整数类型,另一种类型是
对应的无符号整数类型,,该值可在中表示
两种类型强>
一种类型是指向void的指针,另一种类型是指向字符的指针
类型
另一方面,这个答案也说明了printf
另一方面,您得到了printf(§7.19.6.1/9)的规范:
如果任何参数不是相应的
转换规范,行为未定义。“
因此,首先他引用了关于va_-arg
的引文,然后是关于printf
的引文。他似乎也不清楚。另一个答案提到,尽管有va_-arg
文档,但无论如何这违反了printf
合同。请看这条线索。我感到困惑
因此,我的问题基本上是在任何情况下,我给出的代码是否是未定义的行为?或者例如对于
v1
的值,可以用int
表示,这不是未定义的行为(如我引用的一个答案所述)
也可能是因为我的代码很旧,可能是因为标准的旧版本不是未定义的行为?这真的很简单:
sprintf
中的格式说明符必须与传递的参数类型匹配。请不要试图推测此规则的例外情况
由于DWORD是无符号长
且%d
不是无符号长
的正确格式说明符,因此程序的行为是未定义的。您必须使用%lu
。由于DWORD
不是标准类型,您应该包括一行
static_assert(std::is_same<DWORD, unsigned long>::value, "DWORD is not an unsigned long");
static_断言(std::is_same::value,“DWORD不是无符号长字符串”);
在程序中的某个地方。
DWORD
被定义为无符号32位整数[]
无符号长
保证至少为32位无符号整数[]
因此,您始终可以将DWORD
赋值给无符号长字符
,而不会丢失精度,因此您可以将无符号长字符说明符与printf
等一起使用,并将参数显式转换为无符号长字符
另一种选择是使用保证等于
DWORD
的std::uint32_t
,并在printf
中使用该格式说明符,我认为DWORD
保证为32位无符号整数,因此甚至最好转换为std::uint32_t
,而不是使用无符号long
。我的MSVC平台有“typedef unsigned long DWORD;“是的,因为在MSVC中,unsigned long
正好是32位。在GCC或任何其他编译器中都不需要这样。不,不,不。大小无关紧要。%d
表示int
,%lu
表示unsigned long
。即使使用%d
表示long
也可能是1的复数。”ent,int
可能是2的补码,但大小可能是相同的!不要做这些假设。只需修改代码。我会使用std::stringstream
和来回答这个问题没有错。再加上一个。但无法逃避这样一个事实,即程序的行为是未定义的。@Bathsheba:我明白了,但我知道因此,其他答案的海报链接似乎声称这是安全的仔细阅读标准后发现它是不安全的。你真的应该在你的开发流程中安排一个修复程序。@Bathsheba:还有,标准是否适用于我的代码,我的意思是,如果我的代码是旧的,而UB可能是最近在标准中引入的呢?遗憾的是,不是:ev在我的C大学时代(20世纪90年代)PrTrF参数不匹配是不明确的。我想我们已经确定它是未定义的行为。但是,我的答案不是直接解决这个问题,它只给出了一个符合标准的方法。另一种方式回答这个问题:如果我可以编写一个完全符合C++标准的编译器,重新格式化硬盘,吃YO。你的猫,或者诸如此类的东西,如果它遇到你的代码,不管它多么荒谬,那么你的程序是未定义的。