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