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

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

问题描述

我应该使用哪个格式说明符来打印变量的地址?我对以下拍品感到困惑.

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

%u-无符号整数

%u - unsigned integer

%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 *地址的位表示形式与同一存储位置的"其他任何指针"地址的位表示形式不同将很重要.这将是字寻址的机器,而不是字节寻址的机器.这些机器如今并不常见(可能不可用),但是我大学毕业后研究的第一台机器就是这样的机器(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 <inttypes.h>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 "\n", (uintptr_t)your_pointer);

这使您可以微调表示以适合自己.我选择将十六进制数字用大写字母表示,以使数字一致地具有相同的高度,并因此出现0xA1B2CDEF开头的特征倾角,而不是像0xa1b2cdef那样沿数字上下倾角.不过,您可以在非常广泛的范围内进行选择. GCC明确建议使用(uintptr_t)强制转换,因为它可以在编译时读取格式字符串.我认为,请求演员表是正确的,尽管我敢肯定有些人会忽略警告并在大多数情况下逃避它.

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类型

§6.2.5 Types

¶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, 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天全站免登陆