【问题标题】:Some basic questions about pointers in C and pointer size关于 C 中的指针和指针大小的一些基本问题
【发布时间】:2021-09-07 23:55:44
【问题描述】:

在下面使用this在线编译器的C代码中,当我将指针地址增加一时,实际地址增加了四。因为数据类型是int。

#include <stdio.h>

int main()
{
    int my_array[3] = {0, 1, 2};
    int* p_array = my_array;
    
    printf("%p \n", p_array);
    
    p_array = ++p_array;
    
    printf("%p \n", p_array);

    return 0;
}

编译后的输出:

0x7ffeb9ba5814 
0x7ffeb9ba5818

我有两个问题:

  1. 是否可以使用指针直接访问/指向地址 0x7ffeb9ba5815 处的单个字节? (不使用按位运算)

  2. 为什么上面例子中的地址指针是6字节的,比如0x7ffeb9ba5818? (我虽然地址是 4 或 8 个字节)

【问题讨论】:

  • p_array = ++p_array; 是未定义的行为。你来这里的目的是什么?增加指针?
  • 1. ((unsigned char *)p_array)[1] = your_value;
  • p_array = ++p_array;:我认为你的意图是p_array++;。请确认。
  • @Jabberwocky 我认为他的意图只是p_array++;p_array += 1;
  • @HamzaJadid p_array = ++p_array 是未定义的行为,请阅读:stackoverflow.com/questions/949433/…

标签: c


【解决方案1】:

首先,我假设您的意思是 ++p_array 而不是 p_array = ++p_array,因为这是未定义的行为。

  1. 是的,是的。将指针转换为 (char*) 类型(或者如果使用 GCC,也可以选择 (void*)),该指针将以 1 的步长增加和减少:
int *a = 0;
a++; // a is now 4
char *b = (char*) a;
b++; // b is now 5
  1. 它们实际上是 8 个字节,但前两个字节是零。打印时,它们会被格式化为尽可能少的数字,就像你写数字 200 时一样,你不会写像 0000200 这样的东西。

【讨论】:

    【解决方案2】:
    1. 是的,例如,您可以将地址转换为指向char 的指针(在 C 中是字节的同义词!)并访问它:

      char *cp = (char *) p_array;
      cp++;
      printf("%p\n", (void *) cp);
      
    2. 它们不是 6 个字节;打印地址只是省略了前导零,与以十进制打印123 相同,而不是0…0000000123。实际上,第一种情况下指针的值是0x00007ffeb9ba5814

    【讨论】:

    • 是 0x00007ffeb9ba5814 还是 0x007ffeb9ba5814?你的现在是 7 字节
    • @GNZ 是的,我忘记了两个零。
    【解决方案3】:

    如果您有一个指向T 类型对象的指针,则将该指针加1 会产生该类型的下一个对象 的地址。例如,假设以下声明:

    char *cp  = (char *)  0x8000;
    short *sp = (short *) 0x8000;
    long *lp  = (long *)  0x8000;
    

    那么以下都是真的:

    Address    char           short         long
    –––––––    +–––+          +–––+         +–––+
    0x8000     |   | cp       |   | sp      |   | lp
               +–––+          + – +         + - +
    0x8001     |   | cp + 1   |   |         |   |
               +–––+          +–––+         + - +
    0x8002     |   | cp + 2   |   | sp + 1  |   |
               +–––+          + - +         + - +
    0x8003     |   | cp + 3   |   |         |   |
               +–––+          +–––+         +–––+
    0x8004     |   | cp + 4   |   | sp + 2  |   | lp + 1
               +–––+          + - +         + - +
                ...            ...           ...
    

    是否可以使用指针直接访问/指向地址 0x7ffeb9ba5815 处的单个字节? (不使用按位运算)

    是的 - 将其转换为 char *unsigned char *

    unsigned char *ucp = ((unsigned char *) my_array + 1);
    

    为什么上面例子中的地址指针是6字节的,比如0x7ffeb9ba5818? (我虽然地址是 4 或 8 个字节)

    %p 转换说明符不打印任何前导 0 - 实际值为 0x00007ffeb9ba5818

    【讨论】:

    • 我觉得这个答案很好地说明了底层的指针算法。尽管 OP 似乎知道指针运算,但问题表明他们对这个概念的掌握并不那么牢固,这个答案有助于解决这个问题。
    【解决方案4】:

    比如0x7ffeb9ba5818?

    这是 48 位虚拟地址区域。就在中间以下。喜欢 1000 中的 491。

    printf("%p %p %p %p %p %p %p\n",
             0, 1, 16, 255, -1, -1L, (1L<<48)/2-1);
    

    打印:

    (nil) 0x1 0x10 0xff 0xffffffff 0xffffffffffffffff 0x7fffffffffff
    

    不仅前导零被抑制!本身也是 0。

    0x7fffffffffff 是 140 TB。虚拟。

    使用下一个分页级别 (5),您将看到更少的前导零。

    【讨论】:

      猜你喜欢
      • 2011-12-09
      • 1970-01-01
      • 2014-05-13
      • 1970-01-01
      • 1970-01-01
      • 2023-01-08
      • 1970-01-01
      • 2017-05-13
      • 1970-01-01
      相关资源
      最近更新 更多