【问题标题】:How to printf a memory address in C如何在C中打印内存地址
【发布时间】:2015-08-01 23:05:03
【问题描述】:

我的代码是:

#include <stdio.h>
#include <string.h>

void main()
    {
    char string[10];
    int A = -73;
    unsigned int B = 31337;

    strcpy(string, "sample");

    // printing with different formats
    printf("[A] Dec: %d, Hex: %x, Unsigned: %u\n", A,A,A);
    printf("[B] Dec: %d, Hex: %x, Unsigned: %u\n", B,B,B);
    printf("[field width on B] 3: '%3u', 10: '%10u', '%08u'\n", B,B,B);

    // Example of unary address operator (dereferencing) and a %x
    // format string 
    printf("variable A is at address: %08x\n", &A);

我正在使用 linux mint 中的终端进行编译,当我尝试使用 gcc 进行编译时,我收到以下错误消息:

basicStringFormatting.c: In function ‘main’:
basicStringFormatting.c:18:2: warning: format ‘%x’ expects argument
of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("variable A is at address: %08x\n", &A);

我要做的就是打印变量 A 的内存地址。

【问题讨论】:

  • void main() 应该是 int main(void)。如果您的书、教程或讲师告诉您使用 void main(),请找到更好的。
  • @KeithThompson 这有什么关系?
  • @PrakharAgrawal:这很重要,因为 1989 年 ANSI C 标准引入了 void 关键字,也指定 main 函数可以定义为 int main(void) { /* ... */ }。它没有提及void main(),并且符合要求的实现可能会拒绝它。有很多书籍和教程建议使用void main();这强烈表明作者确实不太了解该语言。 (这适用于托管实现。对于独立实现,程序不在操作系统下运行,程序入口点是实现定义的。
  • @PrakharAgrawal:另见comp.lang.c FAQ,从问题 11.12a 开始。

标签: c pointers printf memory-address unary-operator


【解决方案1】:

使用格式说明符%p:

printf("variable A is at address: %p\n", (void*)&A);

标准要求参数是void* 类型的%p 说明符。因为,printf 是一个可变参数函数,所以没有从 T *void * 的隐式转换,这对于 C 中的任何非可变参数函数都会隐式发生。因此,需要强制转换。引用标准:

7.21.6 格式化输入/输出函数(C11 草案)

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

而您使用的是%x,它需要unsigned int,而&amp;A 的类型是int *。您可以阅读printf from the manual 的格式说明符。 printf 中的格式说明符不匹配导致undefined behaviour

【讨论】:

  • 重要的事情要投给void *
  • @Blue Moon - 为什么施放 (void *) 很重要?
  • 我在一个小应用程序中测试了使用和不使用强制转换的变量的打印地址,但得到了相同的结果。但很明显,标准的声明( p 参数应是指向 void 的指针)几乎没有解释的余地​​。谢谢。
  • 那么所有指针都可以转换为void *吗?我认为答案是肯定的,但可能不是函数指针。
  • @chux 没有打印函数指针地址的标准方法。转换为void * 并使用%p 打印,或者如您所说,可以转换为uintmax_t 并打印可能在实践中起作用。但是没有这样的保证它会起作用(它也不符合标准)。该标准将函数指针的表示保留为实现定义,并且不能保证函数指针值是某种整数。所以强制转换为任何整数类型都可能不起作用。
【解决方案2】:

使用带有长度说明符的%x 来打印intunsigned int 而编译器不会抱怨强制转换的解决方法是使用malloc:

unsigned int* D = malloc(sizeof(unsigned int)); // Allocates D
unsigned int D_address = *((unsigned int*) &D); // D address for %08x without warning
*D = 75; // D value
printf("variable D is at address: %p / 0x%08x with value: %u\n", D, D_address, *D);

或者,您可以使用 gcc -w 标志进行编译以抑制那些强制转换警告。

编辑 64 位地址:

unsigned long* D = malloc(sizeof(unsigned long)); // Allocates D
unsigned long D_address = *((unsigned long*) &D); // D address for %016lx without warning
*D = ULONG_MAX; // D value
printf("variable D is at address: %p / 0x%016lx with value: %lu\n", D, D_address, *D);

【讨论】:

  • 小心这个;它假定为 32 位指针,不适用于 64 位。
猜你喜欢
  • 2017-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多