鱼C论坛

 找回密码
 立即注册
查看: 458|回复: 9

[已解决]VS2005中sprintf函数结果不正确

[复制链接]
发表于 2025-1-23 16:58:49 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
下面的代码:
  1. /*------------------------------------------
  2.    RANDRECT.C -- Displays Random Rectangles
  3.                  (c) Charles Petzold, 1998
  4.   ------------------------------------------*/

  5. #include <windows.h>
  6. #include <stdlib.h>           // for the rand function
  7. #include <stdio.h>
  8. #include <time.h>

  9. HDC hdc;
  10. long int times;

  11. LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
  12. void DrawRectangle (HWND) ;

  13. int cxClient, cyClient ;

  14. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
  15.                     PSTR szCmdLine, int iCmdShow)
  16. {
  17.      static TCHAR szAppName[] = TEXT ("RandRect") ;
  18.      HWND         hwnd ;
  19.      MSG          msg ;
  20.      WNDCLASS     wndclass ;
  21.      
  22.      wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
  23.      wndclass.lpfnWndProc   = WndProc ;
  24.      wndclass.cbClsExtra    = 0 ;
  25.      wndclass.cbWndExtra    = 0 ;
  26.      wndclass.hInstance     = hInstance ;
  27.      wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
  28.      wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
  29.      wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
  30.      wndclass.lpszMenuName  = NULL ;
  31.      wndclass.lpszClassName = szAppName ;
  32.      
  33.      if (!RegisterClass (&wndclass))
  34.      {
  35.           MessageBox (NULL, TEXT ("This program requires Windows NT!"),
  36.                       szAppName, MB_ICONERROR) ;
  37.           return 0 ;
  38.      }
  39.      
  40.      hwnd = CreateWindow (szAppName, TEXT ("Random Rectangles"),
  41.                           WS_OVERLAPPEDWINDOW,
  42.                           CW_USEDEFAULT, CW_USEDEFAULT,
  43.                           CW_USEDEFAULT, CW_USEDEFAULT,
  44.                           NULL, NULL, hInstance, NULL) ;
  45.      
  46.      ShowWindow (hwnd, iCmdShow) ;
  47.      UpdateWindow (hwnd) ;
  48.      
  49.      while (TRUE)
  50.      {
  51.           if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
  52.           {
  53.                if (msg.message == WM_QUIT)
  54.                     break ;
  55.                
  56.                TranslateMessage (&msg) ;
  57.                DispatchMessage (&msg) ;
  58.           }
  59.           else
  60.                DrawRectangle (hwnd) ;
  61.      }
  62.      return msg.wParam ;
  63. }

  64. LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
  65. {
  66.          char strTimes[256] = { 0 };
  67.          static time_t starTime, endTime;

  68.      switch (iMsg)
  69.      {
  70.          case WM_CREATE:
  71.                   hdc = GetDC (hwnd) ;
  72.                   starTime = time(NULL);

  73.                   return 0;

  74.      case WM_SIZE:
  75.           cxClient = LOWORD (lParam) ;
  76.           cyClient = HIWORD (lParam) ;

  77.           return 0 ;

  78.          case WM_CLOSE:
  79.                   endTime = time(NULL);
  80.                   sprintf(strTimes, "用时 = %d 秒\n矩形数 = %d\n", endTime - starTime, times);
  81.                   MessageBox(hwnd, strTimes, "结果", MB_OK | MB_ICONINFORMATION);
  82.                   ReleaseDC (hwnd, hdc);
  83.                   DestroyWindow(hwnd);

  84.                   return 0;
  85.          
  86.      case WM_DESTROY:
  87.           PostQuitMessage (0) ;

  88.           return 0 ;
  89.      }
  90.      return DefWindowProc (hwnd, iMsg, wParam, lParam) ;
  91. }

  92. void DrawRectangle (HWND hwnd)
  93. {
  94.      HBRUSH hBrush ;
  95.      //HDC    hdc ;
  96.      RECT   rect ;
  97.      
  98.      if (cxClient == 0 || cyClient == 0)
  99.           return ;
  100.      
  101.      SetRect (&rect, rand () % cxClient, rand () % cyClient,
  102.                      rand () % cxClient, rand () % cyClient) ;
  103.      
  104.      hBrush = CreateSolidBrush (
  105.                     RGB (rand () % 256, rand () % 256, rand () % 256)) ;

  106.      //hdc = GetDC (hwnd) ;
  107.      FillRect (hdc, &rect, hBrush) ;
  108.      //ReleaseDC (hwnd, hdc) ;
  109.      DeleteObject (hBrush) ;
  110.          times++;
  111.          Sleep(1);
  112. }     
复制代码


以上代码中 sprintf函数调用中的times, 用VS2005编译, 结果总是为0,  但是用VC6编译能得以正确结果(生成的矩形数), 问题出的哪里?
最佳答案
2025-1-23 18:36:37
七彩云南 发表于 2025-1-23 17:40
怎么把DrawRectangle函数里的静态变量传给WinMain中的sprintf呢?
  1. #include <windows.h>
  2. #include <stdio.h>

  3. // DrawRectangle 函数
  4. int DrawRectangle() {
  5.     static int staticVar = 0; // 静态变量
  6.     return staticVar++;       // 返回静态变量的值并自增
  7. }

  8. // WinMain 函数
  9. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
  10.     int value = DrawRectangle(); // 获取 DrawRectangle 函数的返回值

  11.     char buffer[256];
  12.     sprintf(buffer, "Static Variable Value: %d", value); // 使用返回值
  13.     MessageBox(NULL, buffer, "Message", MB_OK);

  14.     return 0;
  15. }
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2025-1-23 17:00:21 | 显示全部楼层
在您的代码中,问题的根源在于 `sprintf` 函数用于格式化字符串时,参数类型不匹配。在C语言中,`sprintf` 函数对于 `"%d"` 需要一个 `int` 类型的参数。然而,`times` 是 `long int` 类型(通常是 64 位),而 `time_t` 类型也是平台相关的。因此,您需要确保正确使用的格式化符号以匹配这些类型。

通过确保 `sprintf` 使用正确的格式化字符串可以解决此问题:

1. 将 `sprintf` 函数的格式化字符串更改为匹配 `long int` 类型。
2. 使用 `"%ld"` 来格式化 `long int` 类型的数据。


以下是修正后的代码:

  1. char strTimes[100] = { 0 }; // 确保有足够空间存储结果字符串
  2. static time_t starTime, endTime;

  3. ...

  4. case WM_CLOSE:
  5.      endTime = time(NULL);
  6.      sprintf(strTimes, "用时 = %ld 秒\n矩形数 = %ld\n", (long)(endTime - starTime), times);
  7.      MessageBox(hwnd, strTimes, "结果", MB_OK | MB_ICONINFORMATION);
  8.      ReleaseDC (hwnd, hdc);
  9.      DestroyWindow(hwnd);
  10.      return 0;
复制代码


这样调整后,`sprintf` 函数应该会正确地输出 `times` 的值。

另外,要确保字符串缓冲区 `strTimes` 的大小是足够的,以便能够存储格式化后的字符串。此处我将其设定为 100 字符长度,只是为了确保足够空间以避免缓冲区溢出问题,您可以根据实际需要调整。

如果还有其他问题,请告诉我!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-1-23 17:16:01 | 显示全部楼层
但是我把times 定义为int  输出时使用 %d ,结果还是为0;

同样的把times定义为long long int, 输出时使用 %lld, 结果仍然是0;

以上情况出现在VSS2005中, VC6能得出正确结果.
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2025-1-23 17:16:37 | 显示全部楼层
七彩云南 发表于 2025-01-23 17:16
但是我把times 定义为int  输出时使用 %d ,结果还是为 ...


这个问题可能与 `sprintf` 在不同编译器版本中的实现或编译器设置有关。在Visual Studio 2005中,新的C运行库可能会引入一些行为上的差异。以下是一些建议的排查和修复步骤:

1. **确保时间计算的正确性**:由于您提到 `times` 总是为0,请确保在代码中 `times` 变量实际被增量。仔细检查相关逻辑,比如在 `DrawRectangle` 中增加 `times++` 代码。

2. **字符串缓冲区问题**:确保 `strTimes` 的大小足够大,以包含格式化后的结果。此缓冲区需要能够容纳最长的字符串。设定一个合理的缓冲区大小,如:

  
  1. char strTimes[100];
复制代码


3. **调试输出**:在 `WM_CLOSE` 之前,输出或打断点检查 `times` 的值,以确保在 sprintf 之前它是正确的。例如,您可以在调试模式下通过直接输出到控制台或通过其他方法来检查 `times` 的值。

4. **调用 _set_SSE2_enable(0)**:在一些特定旧系统上,问题可能与浮点运算相关,可以尝试调用 `_set_SSE2_enable(0)`。但大多数情况下这与您的问题无关。

5. **Visual Studio 设置**:检查编译器设置,确保没有设置特定选项从而导致对 `sprintf` 行为的影响。

以下是一些调试代码的例子:

  1. #include <stdio.h>

  2. // 在 WM_CLOSE 之前打印 times
  3. fprintf(stdout, "times = %d\n", times);

  4. // 或者在调试器中设置断点查看 times 的值
复制代码


如果问题仍然存在,请逐步验证每一步以找到根源。确保没有遗漏初始化或者条件竞争等潜在错误。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2025-1-23 17:20:16 | 显示全部楼层
  1. 使用局部静态变量
  2. 将 times 定义为局部静态变量,而不是全局变量。这样可以确保 times 的值在函数调用之间保持不变。
  3. 修改代码如下:
  4. void DrawRectangle(HWND hwnd)
  5. {
  6.     static long int times = 0;  // 定义为局部静态变量
  7.     HBRUSH hBrush;
  8.     RECT rect;

  9.     if (cxClient == 0 || cyClient == 0)
  10.         return;

  11.     SetRect(&rect, rand() % cxClient, rand() % cyClient,
  12.                      rand() % cxClient, rand() % cyClient);

  13.     hBrush = CreateSolidBrush(
  14.                 RGB(rand() % 256, rand() % 256, rand() % 256));

  15.     FillRect(hdc, &rect, hBrush);
  16.     DeleteObject(hBrush);
  17.     times++;
  18.     Sleep(1);
  19. }
  20. 然后在 WM_CLOSE 消息中,将 times 的值传递给 MessageBox:
  21. case WM_CLOSE:
  22.     endTime = time(NULL);
  23.     sprintf(strTimes, "用时 = %d 秒\n矩形数 = %d\n", endTime - starTime, times);
  24.     MessageBox(hwnd, strTimes, "结果", MB_OK | MB_ICONINFORMATION);
  25.     ReleaseDC(hwnd, hdc);
  26.     DestroyWindow(hwnd);
  27.     return 0;
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-1-23 17:40:38 | 显示全部楼层

怎么把DrawRectangle函数里的静态变量传给WinMain中的sprintf呢?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-1-23 18:35:18 | 显示全部楼层
我用:
  1. sprintf(strTimes, "矩形数: %d\n", times);
复制代码


替换
  1. sprintf(strTimes, "用时 = %d 秒\n矩形数 = %d\n", endTime - starTime, times);
复制代码


即只传 times 一个变量给 sprintf函数时, 可以正确输出 times 的值, 但传2 个变量时  times 的值总是0.
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2025-1-23 18:36:37 | 显示全部楼层    本楼为最佳答案   
七彩云南 发表于 2025-1-23 17:40
怎么把DrawRectangle函数里的静态变量传给WinMain中的sprintf呢?
  1. #include <windows.h>
  2. #include <stdio.h>

  3. // DrawRectangle 函数
  4. int DrawRectangle() {
  5.     static int staticVar = 0; // 静态变量
  6.     return staticVar++;       // 返回静态变量的值并自增
  7. }

  8. // WinMain 函数
  9. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
  10.     int value = DrawRectangle(); // 获取 DrawRectangle 函数的返回值

  11.     char buffer[256];
  12.     sprintf(buffer, "Static Variable Value: %d", value); // 使用返回值
  13.     MessageBox(NULL, buffer, "Message", MB_OK);

  14.     return 0;
  15. }
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-1-23 19:10:27 | 显示全部楼层
真见鬼了.

把两个参数交换下位置, 先输出矩形数, 后输出时间
即把sprintf改为:
  1. sprintf(strTimes, "矩形数 = %d \n时间 = %d 秒\n", times, endTime - starTime);
复制代码


可以得到正确输出.
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-1-23 19:56:32 | 显示全部楼层
增加一个中间变量保存 endTime - starTime, 用于保存时间变量的值, 再把这个变量作为sprintf参数:
即:
  1. int shijian;

  2. shijian = endTime - starTime;
  3. sprintf(strTimes, "时间 : %d 秒\n矩形数 : %d\n", shijian, times)
复制代码

可以正确输出.

另:GCC11.4.0上没有这个问题, 可以正确执行并正确输出.
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-22 07:52

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表