GetVolumeInformation() 产生不同的磁盘序列号
Different disk serial number result from GetVolumeInformation()
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);
谢谢。
这两行会给你 undefined behavior:
char* disk_serialANSI;
sprintf(disk_serialANSI, "%d", disk_serialINT);
你声明了一个指针变量,但实际上并没有让它指向任何地方。未初始化的局部变量有一个不确定的值(实际上它看起来是随机的),并且通过使用那个未初始化的指针你不知道 哪里 sprintf
调用将写入。
由于您使用 C++ 编程,因此有几个解决方案。
老套的做法是把disk_serialANSI
做成一个字符数组,大到可以放数字(包括字符串终止符)。另一种方法是手动为指针分配内存,然后在完成后再次释放该内存。
使用std::ostringstream
格式化数据得到std::string
.
直接用std::to_string
转成字符串
除了 Joachim 所说的,您没有正确传递序列号。您应该传递一个指向单个值的指针。
DWORD disk_serialINT;
GetVolumeInformationA(NULL, NULL, NULL, &disk_serialINT, NULL, NULL, NULL, NULL);
在您的代码中,您在这里所做的事情使情况更加复杂:
sprintf(disk_serialANSI, "%d", disk_serialINT);
忽略 Joachim 的回答涵盖的未初始化变量 disk_serialANSI
,您正在传递指向 "%d"
格式字符串的指针。一旦将 disk_serialINT
更改为单一值,事情就会变得更好。但是,您将无符号值传递给单一格式字符串。
是时候放弃这些粗糙的 C 格式化函数并使用 C++ 标准库在整数值和文本之间进行转换了。
最后要强调的一点是,您必须检查调用 Win32 API 的 return 值。您不知道函数调用是否成功。你不能假设它确实如此。这些都包含在文档中: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;
}
万一有人来看这段代码,这里的解决方案是我的看法:
问题#1
DWORD disk_serialINT[MAX_PATH + 1];
- 在您只需要一个值时声明一个包含
DWORD
个值的数组。
- 使用
MAX_PATH
宏(并向其加 1)但不了解它的用途。
- 不知道类型(在
DWORD
类型为 unsigned 时命名变量 INT
)。
- 不理解问题域(将变量命名为
disk_serial
而实际上它是 卷 序列号)。
问题 #2
GetVolumeInformationA(NULL, NULL, NULL, disk_serialINT, NULL, NULL, NULL, NULL);
- 无错误处理(不检查函数 return 失败值)。
- 不理解按值传递参数和按引用传递参数的区别(不传递
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;
}
}
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);
谢谢。
这两行会给你 undefined behavior:
char* disk_serialANSI;
sprintf(disk_serialANSI, "%d", disk_serialINT);
你声明了一个指针变量,但实际上并没有让它指向任何地方。未初始化的局部变量有一个不确定的值(实际上它看起来是随机的),并且通过使用那个未初始化的指针你不知道 哪里 sprintf
调用将写入。
由于您使用 C++ 编程,因此有几个解决方案。
老套的做法是把
disk_serialANSI
做成一个字符数组,大到可以放数字(包括字符串终止符)。另一种方法是手动为指针分配内存,然后在完成后再次释放该内存。使用
std::ostringstream
格式化数据得到std::string
.直接用
std::to_string
转成字符串
除了 Joachim 所说的,您没有正确传递序列号。您应该传递一个指向单个值的指针。
DWORD disk_serialINT;
GetVolumeInformationA(NULL, NULL, NULL, &disk_serialINT, NULL, NULL, NULL, NULL);
在您的代码中,您在这里所做的事情使情况更加复杂:
sprintf(disk_serialANSI, "%d", disk_serialINT);
忽略 Joachim 的回答涵盖的未初始化变量 disk_serialANSI
,您正在传递指向 "%d"
格式字符串的指针。一旦将 disk_serialINT
更改为单一值,事情就会变得更好。但是,您将无符号值传递给单一格式字符串。
是时候放弃这些粗糙的 C 格式化函数并使用 C++ 标准库在整数值和文本之间进行转换了。
最后要强调的一点是,您必须检查调用 Win32 API 的 return 值。您不知道函数调用是否成功。你不能假设它确实如此。这些都包含在文档中: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;
}
万一有人来看这段代码,这里的解决方案是我的看法:
问题#1
DWORD disk_serialINT[MAX_PATH + 1];
- 在您只需要一个值时声明一个包含
DWORD
个值的数组。 - 使用
MAX_PATH
宏(并向其加 1)但不了解它的用途。 - 不知道类型(在
DWORD
类型为 unsigned 时命名变量INT
)。 - 不理解问题域(将变量命名为
disk_serial
而实际上它是 卷 序列号)。
问题 #2
GetVolumeInformationA(NULL, NULL, NULL, disk_serialINT, NULL, NULL, NULL, NULL);
- 无错误处理(不检查函数 return 失败值)。
- 不理解按值传递参数和按引用传递参数的区别(不传递
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;
}
}