3
DWORD disk_serialINT[MAX_PATH + 1];
GetVolumeInformationA(NULL, NULL, NULL, disk_serialINT, NULL, NULL, NULL, NULL);
char* disk_serialANSI;
sprintf(disk_serialANSI, "%d", disk_serialINT);
std::string HDDserial = disk_serialANSI;

这是我获取硬盘序列号的一段代码,但问题是每次程序执行时值都不同。有人可以解释一下吗?

解决了:

DWORD disk_serialINT;
GetVolumeInformationA(NULL, NULL, NULL, &disk_serialINT, NULL, NULL, NULL, NULL);
std::string HDDserial = std::to_string(disk_serialINT);

谢谢。

4

3 回答 3

8

These two lines will give you undefined behavior:

char* disk_serialANSI;
sprintf(disk_serialANSI, "%d", disk_serialINT);

You declare a pointer variable, but you don't actually make it point anywhere. Uninitialized local variables have an indeterminate value (in practice it will be seemingly random), and by using that uninitialized pointer you don't know where the sprintf call will write.


Since you're programming in C++ there are a couple of solutions.

  • The old-fashioned is to make disk_serialANSI an array of characters, big enough to hold the number (including string terminator). An alternative is to manually allocate memory for the pointer, and then free that memory again when you're done with it.

  • Using std::ostringstream to format the data and get a std::string.

  • Using std::to_string to convert to a string directly.

  • Use Boost Lexical cast.

于 2015-01-28T13:41:04.437 回答
2

除了 Joachim 所说,您没有正确传递序列号。您应该传递一个指向单个值的指针。

DWORD disk_serialINT;
GetVolumeInformationA(NULL, NULL, NULL, &disk_serialINT, NULL, NULL, NULL, NULL);

在您的代码中,这与您在此处所做的事情有关:

sprintf(disk_serialANSI, "%d", disk_serialINT);

忽略disk_serialANSIJoachim 的回答所涵盖的未初始化变量,您将传递一个指向"%d"格式字符串的指针。一旦您更改disk_serialINT为单一值,事情会变得更好。但是,您将无符号值传递给单个格式字符串。

是时候放弃这些粗糙的 C 格式化函数并使用 C++ 标准库在整数值和文本之间进行转换了。

最后要强调的一点是,您必须检查对 Win32 API 的调用的返回值。你不知道函数调用是否成功。你不能假设它确实如此。这一切都包含在文档中:https ://msdn.microsoft.com/en-us/library/windows/desktop/aa364993.aspx

该程序打印包含当前目录的卷的序列号:

#include <Windows.h>
#include <iostream>

int main()
{
    DWORD disk_serialINT;
    if (!GetVolumeInformationA(NULL, NULL, NULL, &disk_serialINT, NULL,
        NULL, NULL, NULL))
    {
        std::cout << "Failed: " << GetLastError() << std::endl;
        return 1;
    }
    std::cout << "Current directory volume serial numnber: " << std::hex 
        << disk_serialINT << std::endl;

    return 0;
}
于 2015-01-28T13:41:41.903 回答
0

万一有人来看这段代码,这里的解决方案就是我的看法:

问题 #1

DWORD disk_serialINT[MAX_PATH + 1];
  • DWORD当您只需要一个值时声明一组值。
  • MAX_PATH在不了解其用途的情况下使用宏(并向其添加 1)。
  • INT不知道类型(当DWORD类型为unsigned时命名变量)。
  • 不了解问题域(disk_serial实际上是序列号时命名变量)。

问题 #2

GetVolumeInformationA(NULL, NULL, NULL, disk_serialINT, NULL, NULL, NULL, NULL);
  • 没有错误处理(不检查函数返回值是否失败)。
  • 不理解按值传递参数和按引用传递参数之间的区别(不传递disk_serialINT变量的地址)。

问题 #3

char* disk_serialANSI;
  • 不了解数组和指针之间的区别。
  • 不了解静态分配和动态分配之间的区别。

问题 #4

sprintf(disk_serialANSI, "%d", disk_serialINT);
  • 使用未初始化的变量disk_serialANSI
  • 使用错误的变量类型(要么使用 数组char,要么保留指针但分配内存并稍后释放它)。
  • 不了解问题域(卷序列号使用错误格式,应该是%08lX)。
  • 不使用安全版本的sprintf.

问题 #5

std::string HDDserial = disk_serialANSI;
  • 没有充分理由混合 C 和 C++。

换句话说,所有典型的初学者程序员错误。希望他们在此期间学到更多,而不仅仅是在 Stack Overflow 上为他们的问题找到答案。

上面已经有 David Heffeman 提供的 C++ 解决方案,所以为了回答的完整性,这里是等效的 C 解决方案:

#include <stdio.h>
#include <windows.h>

int main()
{
    const int VolumeSerialLength = 9; // 8 hex digits + zero termination
    char VolumeSerial[VolumeSerialLength] = { 0 };
    DWORD VolumeSerialNumber;

    if (GetVolumeInformationA(NULL, NULL, NULL, &VolumeSerialNumber, NULL, NULL, NULL, NULL) {
        sprintf_s(VolumeSerial, VolumeSerialLength, "%08lX", VolumeSerialNumber);
        printf("Volume serial number: %8.8s.\n", VolumeSerial);
        return 0;
    } else {
        printf("GetVolumeInformationA() error: %08lX\n", GetLastError());
        return 1;
    }
}
于 2019-11-29T15:41:38.543 回答