C++;printf%p说明符在Linux和Windows中的行为不同 我有一个C++代码,它可以在Linux和Windows上工作。p>
部分代码包括使用C++;printf%p说明符在Linux和Windows中的行为不同 我有一个C++代码,它可以在Linux和Windows上工作。p>,c++,linux,windows,portability,C++,Linux,Windows,Portability,部分代码包括使用vsnprintf,以便使用格式字符串和参数获取字符串 我注意到,每当格式字符串包含%p时,结果在Linux和Windows上都是不同的-Windows不会在结果前面加0x,而Linux会,而且Windows使用大写字母作为地址的字母,而Linux使用小写字母 我找不到使两个版本相同的标志 我的首选是使Linux版本的行为类似于Windows版本(因为Windows代码是原始的,所以程序的行为应该是这样的) 如果无法在Linux中更改vsnprintf的行为,我希望有一种方法在v
vsnprintf
,以便使用格式字符串和参数获取字符串
我注意到,每当格式字符串包含%p时,结果在Linux和Windows上都是不同的-Windows不会在结果前面加0x,而Linux会,而且Windows使用大写字母作为地址的字母,而Linux使用小写字母
我找不到使两个版本相同的标志
我的首选是使Linux版本的行为类似于Windows版本(因为Windows代码是原始的,所以程序的行为应该是这样的)
如果无法在Linux中更改
vsnprintf
的行为,我希望有一种方法在vsnprintf
输出后“修复”包含%p的字符串(以有效的方式) 字符串%p
正在打印。这就是Linux和Windows上行为不同的原因。如果您想要一致的行为,就必须实现自己的版本
使用,我们可以得到一个可以容纳指针的整数。所以我们可以将指针插入其中。请注意,尽管转换将成功,但没有指定值将保留什么
然后,我们可以使用或适当的方式将整数打印为十六进制:
auto*myPointer=。。。;
std::cout字符串%p
打印为。这就是Linux和Windows上行为不同的原因。如果您想要一致的行为,就必须实现自己的版本
使用,我们可以得到一个可以容纳指针的整数。所以我们可以将指针插入其中。请注意,尽管转换将成功,但没有指定值将保留什么
然后,我们可以使用或适当的方式将整数打印为十六进制:
auto*myPointer=。。。;
std::cout正如建议的那样,您可以将指针转换为uintpttr\t
,并根据需要对其进行格式化。这可能是99%的可移植性——因为您可能只关心Linux和Windows,这可能就足够了。(在没有足够大的整数类型来保存指针值而不丢失信息的系统上,它可能会失败。这样的系统不会定义uintpttr\t
。您不太可能遇到这样的系统。)
另一种方法是使用%p
格式将指针格式化为字符串,然后操纵生成的字符串以获得所需的一致结果。创建一个接受void*
参数并返回std::string
的函数可能是有意义的
这是我的尝试(我没有声称这是好的C++代码)。它删除前导的
0x
或0x
(如果存在),并将所有剩余字符映射为大写
如果没有C++11编译器,请调整for
循环
#include <iostream>
#include <string>
#include <cstdio>
#include <cctype>
std::string hex(void* ptr) {
const int big_enough = 100;
char s[big_enough];
std::snprintf(s, sizeof s, "%p", ptr);
std::string result = s;
std::string prefix = result.substr(0, 2);
if (prefix == "0x" || prefix == "0X") {
result = result.substr(2);
}
for (auto &&c : result) {
c = std::toupper((unsigned char)c);
}
return result;
}
int main() {
int n;
int *ptr = &n;
std::printf("Using %%p: %p\n", (void*)ptr);
std::cout << "Using hex(): " << hex((void*)ptr) << "\n";
}
正如建议的那样,您可以将指针转换为uintptr\t
,并根据需要对其进行格式化。这可能是99%的可移植性——因为您可能只关心Linux和Windows,这可能就足够了。(在没有足够大的整数类型来保存指针值而不丢失信息的系统上,它可能会失败。这样的系统不会定义uintpttr\t
。您不太可能遇到这样的系统。)
另一种方法是使用%p
格式将指针格式化为字符串,然后操纵生成的字符串以获得所需的一致结果。创建一个接受void*
参数并返回std::string
的函数可能是有意义的
这是我的尝试(我没有声称这是好的C++代码)。它删除前导的
0x
或0x
(如果存在),并将所有剩余字符映射为大写
如果没有C++11编译器,请调整for
循环
#include <iostream>
#include <string>
#include <cstdio>
#include <cctype>
std::string hex(void* ptr) {
const int big_enough = 100;
char s[big_enough];
std::snprintf(s, sizeof s, "%p", ptr);
std::string result = s;
std::string prefix = result.substr(0, 2);
if (prefix == "0x" || prefix == "0X") {
result = result.substr(2);
}
for (auto &&c : result) {
c = std::toupper((unsigned char)c);
}
return result;
}
int main() {
int n;
int *ptr = &n;
std::printf("Using %%p: %p\n", (void*)ptr);
std::cout << "Using hex(): " << hex((void*)ptr) << "\n";
}
%p
的行为是@Borgleader:不是0x%X
需要类型为无符号int
的参数;给它一个指针具有未定义的行为。如果unsigned int
和指针的大小相同(它们通常不是相同的),它可能会正常工作;这是一种可能的行为,可能是C++的错误。他们是两种不同的语言。你用哪一种?(在极少数情况下,您可能希望编写能正确使用两种语言的代码;如果是这样,请在问题中说明。)@KeithThompson我已更新了问题。它是在C++@Justin中,没有说明指针如何转换为uintptr\u t
。只有与这些的转换才能保证有效。%p
的行为是@Borgleader:不是0x%X
需要类型为无符号int
的参数;给它一个指针具有未定义的行为。如果unsigned int
和指针的大小相同(它们通常不是相同的),它可能会正常工作;这是一种可能的行为,可能是C++的错误。他们是两种不同的语言。你用哪一种?(在极少数情况下,您可能希望编写能正确使用两种语言的代码;如果是这样,请在问题中说明。)@KeithThompson我已更新了问题。它是在C++@Justin中,没有说明指针如何转换为uintptr\u t
。只有转换为/转换为格式字符串才能保证有效。我想尝试此解决方案,但我需要能够在运行时通过编程检测格式字符串中出现的每一个%p
,并将其替换为PRIXPTR
。我该怎么做?(检测很容易,但是如何用宏替换字符串的p
?@darkThoughts注意,格式宏常量是#为字符串文本定义s。例如,在coliru上,PRIxPTR
是sa
Using %p: 0x7ffd6e8ca884
Using hex(): 7FFD6E8CA884