c - C将address转int的规则是什么?

标签 c

我是C初学者,今天在研究指针部分,我发现我可以直接打印一个地址,当使用正确的类型转义器时,我什至可以打印存储在该内存地址中的预期值。

后来,我做了一些实验:

##### CODE PART ######
#include <stdio.h>  // Define several variable types, macros, and functions about standard input/output.

int main () {
    char my_string[] = "address test";
    printf("%s\n", &my_string);
    printf("%p\n", &my_string);
    printf("%d\n", &my_string);
    printf("%x\n", &my_string);
    printf("\n");

    char *p = "pointer string test";
    printf("%s\n", p);
    printf("%p\n", p);
    printf("%d\n", p);
    printf("\n");

    char *p2 = 'p';
    printf("%c\n", p2);
    printf("%p\n", p2);
    printf("%d\n", p2);
    return 0;
}


##### OUTPUT #####
address test
0x7fff58778a7b
1484229243
58778a7b

pointer string test
0x107487f87
122191751

p
0x70
112

一开始我不太理解%d格式输出的行为,但经过更多的观察和实验。我发现 %d 正在转换内存地址的部分十六进制值。

但是my_string的地址省略了0x7fff部分,p的地址省略了0x10部分, 对于 p2 它省略了 0x 部分。在我的认知中,0x是一个十六进制值的首标。

但是我怎么知道在将内存地址转换为 int 时 C 会省略多少数字,就像在 my_stringp 的示例中那样?


PS:我的系统版本是OSX10.10

最佳答案

C 标准 (ISO/IEC 9899:2011) 对指针和整数之间的转换有这样的规定:

6.3 Conversions

6.3.2.3 Pointers

¶5 An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.67)

¶6 Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type.

67) The mapping functions for converting a pointer to an integer or an integer to a pointer are intended to be consistent with the addressing structure of the execution environment.

请注意,指针和整数之间的转换行为是实现定义的,而不是未定义的。但是,除非使用的整数类型是 uintptr_tintptr_t (来自 <stdint.h> — 或 <inttypes.h> ),如果指针的大小和整数类型不匹配,您可能会看到截断效果。如果您在 32 位和 64 位系统之间移动您的代码,您将在某处遇到问题。

在你的代码中,你有 64 位指针(因为你在 Mac OS X 10.10 上,你需要明确指定 -m32 以获得 32 位构建,但你的结果与 64 位一致无论如何都要 build )。当您将这些指针传递给 printf() 时与 %d%x转换规范,您正在请求 printf()打印 32 位数字,因此它会格式化您传递的 64 位中的 32 位。行为不明确;你本身并没有得到转换,但是调用代码(在 main() 中)将一个 64 位指针压入堆栈,被调用代码(printf())从堆栈中读取一个 32 位数量。如果您要求一次调用 printf()应该打印几个值(例如 printf("%d %x\n", p, p); ),你会得到更令人惊讶的结果。

您应该使用如下选项进行编译:

gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
    -Wold-style-definition -Werror …

使用这些选项,您的代码将无法编译;编译器会提示格式字符串和传递的值之间不匹配。当我将您的代码保存到文件中时 noise.c并用 clang 编译它(来自 XCode 7.2,在 Mac OS X 10.10.5 上运行),我得到:

$ /usr/bin/clang -O3 -g  -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
>     -Wold-style-definition -Werror noise.c -o noise
noise.c:5:20: error: format specifies type 'char *' but the argument has type 'char (*)[13]'
      [-Werror,-Wformat]
    printf("%s\n", &my_string);
            ~~     ^~~~~~~~~~
noise.c:7:20: error: format specifies type 'int' but the argument has type 'char (*)[13]' [-Werror,-Wformat]
    printf("%d\n", &my_string);
            ~~     ^~~~~~~~~~
noise.c:8:20: error: format specifies type 'unsigned int' but the argument has type 'char (*)[13]'
      [-Werror,-Wformat]
    printf("%x\n", &my_string);
            ~~     ^~~~~~~~~~
noise.c:14:20: error: format specifies type 'int' but the argument has type 'char *' [-Werror,-Wformat]
    printf("%d\n", p);
            ~~     ^
            %s
noise.c:17:11: error: incompatible integer to pointer conversion initializing 'char *' with an expression of
      type 'int' [-Werror,-Wint-conversion]
    char *p2 = 'p';
          ^    ~~~
noise.c:18:20: error: format specifies type 'int' but the argument has type 'char *' [-Werror,-Wformat]
    printf("%c\n", p2);
            ~~     ^~
            %s
noise.c:20:20: error: format specifies type 'int' but the argument has type 'char *' [-Werror,-Wformat]
    printf("%d\n", p2);
            ~~     ^~
            %s
7 errors generated.
$

编译带有严格的警告,并注意这些警告。

关于c - C将address转int的规则是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34542481/

相关文章:

c++ - 在新数组中存储字符数组地址

c - 在 C 中反转字符串中的单词

c - C 中查找字符串中每个字符出现的次数

c - 麻烦在c中声明一个全局字符串数组

c - 如何在C中显示线程的属性?

gcc 可以生成不同大小的目标代码吗?

C读取二进制文件

c - 使用scanf()时如何区分整数和字符

c - 指针NULL问题

c - 关于制作可执行程序的新手问题