此DWORD相关代码是否未定义行为?

时间:2015-11-12 14:30:29

标签: c++ undefined-behavior

这是我第三次尝试澄清我对这个话题的困惑。但这次我有不同的问题。

我有这段代码

  DWORD v1, v2, v3, Build;
  GetVersion(&v1, &v2, &v3, &Build);
  sprintf(VersionStr, "%d.%d.%d.%d", v1, v2, v3, Build);

这是10年前用Visual Studio编写的。我知道DWORD总是unsigned - 这是真的吗?

现在,here,其中一个答案引用了某些标准版本(此标准版本是否适用于我的代码?),其中提到了va_arg

  

在这一点上,标准并非100%明确。一方面,你得到了    va_arg 的规范,其中说(§7.15.1.1/ 2):

     

如果没有实际的下一个参数,或者type不兼容   实际下一个参数的类型(根据   默认参数促销),行为是未定义的,除了   以下情况:

     

一种类型是有符号整数类型,另一种类型是   相应的无符号整数类型,,该值可表示   两种类型;

     

一种类型是指向void的指针,另一种是指向字符的指针   类型。

另一方面,答案也说明了printf

  

另一方面,你得到 printf (§7.19.6.1/ 9)的规范:

     

如果任何参数不是相应的正确类型   转换规范,行为未定义。“

首先,他引用关于va_arg然后关于printf的引用。他似乎也不清楚。尽管有printf文档,但另一个答案提到这违反了va_arg合同。请看一下线程。我很困惑。

所以我的问题基本上是代码我在任何情况下都提出了未定义的行为?或者,例如<{>,可以在v1 中表示int的值,这不是未定义的行为(如我引用的其中一个答案所述)?

也可能是因为我的代码旧了,可能是旧版本的标准还没有未定义的行为?

2 个答案:

答案 0 :(得分:6)

这非常简单:sprintf 中的格式说明符必须匹配传递的参数类型。请不要试图推销此规则的例外情况。

由于DWORD是unsigned long%d unsigned long的正确格式说明符,因此程序的行为未定义。您必须使用%lu。由于DWORD不是标准类型,因此您应该包含一行

static_assert(std::is_same<DWORD, unsigned long>::value, "DWORD is not an unsigned long");

你计划中的某个地方。

答案 1 :(得分:0)

DWORD被定义为无符号32位整数[MSDN]。

unsigned long保证至少为32位无符号整数[cppreference]。

因此,您始终可以DWORDunsigned long分配printf而不会丢失精度,因此您可以使用带有std::uint32_t的无符号长说明符和类似内容以及显式转换unsigned long的参数。

另一种方法是使用DWORD保证等于printf,并在let url = "YOUR_URL" let afHTTP : AFHTTPRequestSerializer = AFHTTPRequestSerializer() let request: NSMutableURLRequest = afHTTP.multipartFormRequestWithMethod("POST", URLString: url, parameters: nil, constructingBodyWithBlock: {(formData: AFMultipartFormData) in for (index, image) in upImage.enumerate() { let imageData = UIImageJPEGRepresentation(image as UIImage, 0.5)! formData.appendPartWithFileData(imageData, name: "uploaded_file[]", fileName: "imagex\(index)x.png", mimeType: "image/png") } }, error: nil) let managerS : AFURLSessionManager = AFURLSessionManager.init(sessionConfiguration: NSURLSessionConfiguration.defaultSessionConfiguration()) let uploadTask = managerS.uploadTaskWithStreamedRequest(request, progress: nil) { (response, AnyObject, error) -> Void in if (error != nil){ print("error") } } uploadTask.resume() 中使用该格式说明符。