鱼C论坛

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

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

[复制链接]
发表于 昨天 16:58 | 显示全部楼层 |阅读模式

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

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

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

#include <windows.h>
#include <stdlib.h>           // for the rand function
#include <stdio.h>
#include <time.h>

HDC hdc;
long int times;

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

int cxClient, cyClient ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("RandRect") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     wndclass ;
     
     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;
     
     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"),
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }
     
     hwnd = CreateWindow (szAppName, TEXT ("Random Rectangles"),
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;
     
     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;
     
     while (TRUE)
     {
          if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
          {
               if (msg.message == WM_QUIT)
                    break ;
               
               TranslateMessage (&msg) ;
               DispatchMessage (&msg) ;
          }
          else
               DrawRectangle (hwnd) ;
     }
     return msg.wParam ;
}

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

     switch (iMsg)
     {
         case WM_CREATE:
                  hdc = GetDC (hwnd) ;
                  starTime = time(NULL);

                  return 0;

     case WM_SIZE:
          cxClient = LOWORD (lParam) ;
          cyClient = HIWORD (lParam) ;

          return 0 ;

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

                  return 0;
          
     case WM_DESTROY:
          PostQuitMessage (0) ;

          return 0 ;
     }
     return DefWindowProc (hwnd, iMsg, wParam, lParam) ;
}

void DrawRectangle (HWND hwnd)
{
     HBRUSH hBrush ;
     //HDC    hdc ;
     RECT   rect ;
     
     if (cxClient == 0 || cyClient == 0)
          return ;
     
     SetRect (&rect, rand () % cxClient, rand () % cyClient,
                     rand () % cxClient, rand () % cyClient) ;
     
     hBrush = CreateSolidBrush (
                    RGB (rand () % 256, rand () % 256, rand () % 256)) ;

     //hdc = GetDC (hwnd) ;
     FillRect (hdc, &rect, hBrush) ;
     //ReleaseDC (hwnd, hdc) ;
     DeleteObject (hBrush) ;
         times++;
         Sleep(1);
}     

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

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

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

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

    return 0;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

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

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


以下是修正后的代码:
char strTimes[100] = { 0 }; // 确保有足够空间存储结果字符串
static time_t starTime, endTime;

...

case WM_CLOSE:
     endTime = time(NULL);
     sprintf(strTimes, "用时 = %ld 秒\n矩形数 = %ld\n", (long)(endTime - starTime), times);
     MessageBox(hwnd, strTimes, "结果", MB_OK | MB_ICONINFORMATION);
     ReleaseDC (hwnd, hdc);
     DestroyWindow(hwnd);
     return 0;

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

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

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

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

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

以上情况出现在VSS2005中, VC6能得出正确结果.
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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


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

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

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

char strTimes[100];

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

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

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

以下是一些调试代码的例子:
#include <stdio.h>

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

// 或者在调试器中设置断点查看 times 的值

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

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

    if (cxClient == 0 || cyClient == 0)
        return;

    SetRect(&rect, rand() % cxClient, rand() % cyClient,
                     rand() % cxClient, rand() % cyClient);

    hBrush = CreateSolidBrush(
                RGB(rand() % 256, rand() % 256, rand() % 256));

    FillRect(hdc, &rect, hBrush);
    DeleteObject(hBrush);
    times++;
    Sleep(1);
}
然后在 WM_CLOSE 消息中,将 times 的值传递给 MessageBox:
case WM_CLOSE:
    endTime = time(NULL);
    sprintf(strTimes, "用时 = %d 秒\n矩形数 = %d\n", endTime - starTime, times);
    MessageBox(hwnd, strTimes, "结果", MB_OK | MB_ICONINFORMATION);
    ReleaseDC(hwnd, hdc);
    DestroyWindow(hwnd);
    return 0;
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 昨天 17:40 | 显示全部楼层

怎么把DrawRectangle函数里的静态变量传给WinMain中的sprintf呢?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 昨天 18:35 | 显示全部楼层
我用:
sprintf(strTimes, "矩形数: %d\n", times);

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

即只传 times 一个变量给 sprintf函数时, 可以正确输出 times 的值, 但传2 个变量时  times 的值总是0.
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

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

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

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

    return 0;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 昨天 19:10 | 显示全部楼层
真见鬼了.

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

可以得到正确输出.
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

shijian = endTime - starTime;
sprintf(strTimes, "时间 : %d 秒\n矩形数 : %d\n", shijian, times)
可以正确输出.

另:GCC11.4.0上没有这个问题, 可以正确执行并正确输出.
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-1-24 02:17

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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