正确的格式说明符打印指针或地址? [英] Correct format specifier to print pointer or address?

查看:29
本文介绍了正确的格式说明符打印指针或地址?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我应该使用哪种格式说明符来打印变量的地址?我在下面的很多之间感到困惑.

Which format specifier should I be using to print the address of a variable? I am confused between the below lot.

%u - 无符号整数

%x - 十六进制值

%p - 空指针

哪种格式是打印地址的最佳格式?

Which would be the optimum format to print an address?

推荐答案

最简单的答案,假设您不介意不同平台之间的格式变化无常,那就是标准的 %p 表示法.

The simplest answer, assuming you don't mind the vagaries and variations in format between different platforms, is the standard %p notation.

C99 标准 (ISO/IEC 9899:1999) 在 §7.19.6.1 ¶8 中说:

The C99 standard (ISO/IEC 9899:1999) says in §7.19.6.1 ¶8:

p 参数应该是一个指向 void 的指针.指针的值为在实现定义中转换为打印字符序列方式.

p The argument shall be a pointer to void. The value of the pointer is converted to a sequence of printing characters, in an implementation-defined manner.

(在 C11 — ISO/IEC 9899:2011 — 信息在 §7.21.6.1 ¶8.)

(In C11 — ISO/IEC 9899:2011 — the information is in §7.21.6.1 ¶8.)

在某些平台上,这将包含一个前导 0x 而在其他平台上则不会,并且字母可以是小写或大写,而 C 标准甚至没有定义它应该是十六进制输出,虽然我知道没有实现它不是.

On some platforms, that will include a leading 0x and on others it won't, and the letters could be in lower-case or upper-case, and the C standard doesn't even define that it shall be hexadecimal output though I know of no implementation where it is not.

是否应该使用 (void *) 强制转换显式转换指针,这在某种程度上是有争议的.它是明确的,这通常很好(所以这就是我所做的),并且标准说'参数应该是一个指向 void 的指针'.在大多数机器上,您可以省略显式强制转换.但是,对于给定内存位置的 char * 地址的位表示与同一内存的anything else 指针"地址不同的机器,这很重要地点.这将是一个字寻址的机器,而不是字节寻址的机器.现在这样的机器并不常见(可能不可用),但我大学毕业后工作的第一台机器就是这样的机器(ICL Perq).

It is somewhat open to debate whether you should explicitly convert the pointers with a (void *) cast. It is being explicit, which is usually good (so it is what I do), and the standard says 'the argument shall be a pointer to void'. On most machines, you would get away with omitting an explicit cast. However, it would matter on a machine where the bit representation of a char * address for a given memory location is different from the 'anything else pointer' address for the same memory location. This would be a word-addressed, instead of byte-addressed, machine. Such machines are not common (probably not available) these days, but the first machine I worked on after university was one such (ICL Perq).

如果您对 %p 的实现定义行为不满意,请使用 C99 uintptr_t> 代替:

If you aren't happy with the implementation-defined behaviour of %p, then use C99 <inttypes.h> and uintptr_t instead:

printf("0x%" PRIXPTR "
", (uintptr_t)your_pointer);

这允许您微调表示以适合自己.我选择了大写的十六进制数字,这样数字的高度一致,并且 0xA1B2CDEF 开头的特征下降出现,而不像 0xa1b2cdef也沿着数字上下波动.但是,您的选择在非常广泛的范围内.(uintptr_t) 强制转换是 GCC 明确推荐的,因为它可以在编译时读取格式字符串.我认为要求演员表是正确的,尽管我确信有些人会无视警告并在大多数情况下逍遥法外.

This allows you to fine-tune the representation to suit yourself. I chose to have the hex digits in upper-case so that the number is uniformly the same height and the characteristic dip at the start of 0xA1B2CDEF appears thus, not like 0xa1b2cdef which dips up and down along the number too. Your choice though, within very broad limits. The (uintptr_t) cast is unambiguously recommended by GCC when it can read the format string at compile time. I think it is correct to request the cast, though I'm sure there are some who would ignore the warning and get away with it most of the time.

Kerrek 在评论中提问:

Kerrek asks in the comments:

我对标准促销和可变参数有点困惑.所有的指针都被标准提升为 void* 吗?否则,如果 int* 是两个字节,而 void* 是 4 个字节,那么从参数中读取四个字节显然是错误的,非?

I'm a bit confused about standard promotions and variadic arguments. Do all pointers get standard-promoted to void*? Otherwise, if int* were, say, two bytes, and void* were 4 bytes, then it'd clearly be an error to read four bytes from the argument, non?

我有一种错觉,即 C 标准说所有对象指针的大小必须相同,所以 void *int * 不能有不同的大小.但是,我认为 C99 标准的相关部分并没有那么强调(尽管我不知道我建议的实现实际上是错误的):

I was under the illusion that the C standard says that all object pointers must be the same size, so void * and int * cannot be different sizes. However, what I think is the relevant section of the C99 standard is not so emphatic (though I don't know of an implementation where what I suggested is true is actually false):

§6.2.5 类型

¶26 指向 void 的指针应具有与指向字符类型的指针相同的表示和对齐要求.39) 同样,指向兼容类型的限定或非限定版本的指针应具有相同的表示和对齐要求.所有指向结构类型的指针都应具有相同的表示和对齐要求.所有指向联合类型的指针都应具有相同的表示和对齐要求.指向其他类型的指针不需要具有相同的表示或对齐要求.

¶26 A pointer to void shall have the same representation and alignment requirements as a pointer to a character type.39) Similarly, pointers to qualified or unqualified versions of compatible types shall have the same representation and alignment requirements. All pointers to structure types shall have the same representation and alignment requirements as each other. All pointers to union types shall have the same representation and alignment requirements as each other. Pointers to other types need not have the same representation or alignment requirements.

39) 相同的表示和对齐要求意味着作为函数的参数、函数的返回值和联合成员的可互换性.

39) The same representation and alignment requirements are meant to imply interchangeability as arguments to functions, return values from functions, and members of unions.

(C11 在第 6.2.5 节、¶28 和脚注 48 中说的完全相同.)

(C11 says exactly the same in the section §6.2.5, ¶28, and footnote 48.)

因此,所有指向结构的指针必须彼此具有相同的大小,并且必须共享相同的对齐要求,即使指针指向的结构可能具有不同的对齐要求.工会也是如此.字符指针和空指针必须具有相同的大小和对齐要求.指向 int 变体(意味着 unsigned intsigned int)的指针必须具有相同的大小和对齐要求;其他类型也类似.但是 C 标准并没有正式说 sizeof(int *) == sizeof(void *).哦,好吧,SO 有利于让您检查您的假设.

So, all pointers to structures must be the same size as each other, and must share the same alignment requirements, even though the structures the pointers point at may have different alignment requirements. Similarly for unions. Character pointers and void pointers must have the same size and alignment requirements. Pointers to variations on int (meaning unsigned int and signed int) must have the same size and alignment requirements as each other; similarly for other types. But the C standard doesn't formally say that sizeof(int *) == sizeof(void *). Oh well, SO is good for making you inspect your assumptions.

C 标准明确不要求函数指针与对象指针的大小相同.这对于在类似 DOS 的系统上不破坏不同的内存模型是必要的.在那里你可以有 16 位数据指针但有 32 位函数指针,反之亦然.这就是为什么 C 标准不强制要求函数指针可以转换为对象指针,反之亦然.

The C standard definitively does not require function pointers to be the same size as object pointers. That was necessary not to break the different memory models on DOS-like systems. There you could have 16-bit data pointers but 32-bit function pointers, or vice versa. This is why the C standard does not mandate that function pointers can be converted to object pointers and vice versa.

幸运的是(对于以 POSIX 为目标的程序员),POSIX 进入了违规行为,并确实要求函数指针和数据指针的大小相同:

Fortunately (for programmers targetting POSIX), POSIX steps into the breach and does mandate that function pointers and data pointers are the same size:

§2.12.3 指针类型

所有函数指针类型应与指向 void 的类型指针具有相同的表示形式.将函数指针转换为 void * 不应改变表示.可以使用显式强制转换将此类转换产生的 void * 值转换回原始函数指针类型,而不会丢失信息.

All function pointer types shall have the same representation as the type pointer to void. Conversion of a function pointer to void * shall not alter the representation. A void * value resulting from such a conversion can be converted back to the original function pointer type, using an explicit cast, without loss of information.

注意:ISO C 标准不要求这样做,但它是 POSIX 一致性所必需的.

Note: The ISO C standard does not require this, but it is required for POSIX conformance.

因此,当将指针传递给可变参数函数(例如 printf())时,似乎强烈建议显式转换为 void * 以实现代码的最大可靠性.在 POSIX 系统上,将函数指针转换为用于打印的空指针是安全的.在其他系统上,这样做不一定安全,也不一定安全地传递除 void * 以外的指针而不进行强制转换.

So, it does seem that explicit casts to void * are strongly advisable for maximum reliability in the code when passing a pointer to a variadic function such as printf(). On POSIX systems, it is safe to cast a function pointer to a void pointer for printing. On other systems, it is not necessarily safe to do that, nor is it necessarily safe to pass pointers other than void * without a cast.

这篇关于正确的格式说明符打印指针或地址?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆