【问题标题】:Storage of variables and dereferencing them变量的存储和解除引用
【发布时间】:2014-08-11 06:04:25
【问题描述】:

基于C中的以下sn-p

int c1,c2;
printf("%d ",&c1-&c2);

Output : -1
  1. 为什么这段代码没有返回警告,指出格式 %d 期望的类型为 int,但它却得到了 (void *)。
  2. 为什么它返回 -1 作为答案(而不是 1)?即使它减去地址也应该是-4而不是-1。当我将 printf 语句更改为 printf("%d ",&c2 - &c1) 时,我得到 1 而不是任何随机值!为什么?
  3. 如果我将 printf 语句更改为printf("%d ",(int)&c1 - (int)&c2) 我是否将地址类型转换为整数值?这是否意味着存储为十六进制的地址的值现在转换为 int 然后减去?

【问题讨论】:

  • 1)指针类型的区别是有符号整数。
  • 2) 指针2 = 指针1 + 1:指针1 - 指针2 == -1,指针2 - 指针1 == 1
  • @ShafikYaghmour:我的错,已删除。

标签: c casting memory-address pointer-arithmetic


【解决方案1】:

1) 它得到一个int。指向某物的指针减去指向某物的指针是一个整数值(类型ptrdiff_t)。它告诉你有多少元素是两个指向同一个数组的指针。

2) 由于两个指针不指向同一个数组,所以差异是不确定的。可以取任意值。

3) 是的。但是“十六进制”部分不正确。地址以位/二进制形式存储(与整数一样)。改变的是你的程序的解释。这与表示形式无关(十六进制/十进制/八进制/...)。

【讨论】:

  • 1.) 关闭。它不是int,而是ptrdiff_t,它是一个有符号整数类型。请编辑。这是参考:6.5.6 Additive operators ,para 9
  • 但是 print(&c2-&c1) 给出 1。由于行为未定义,它不应该总是一个随机值吗?
  • 未定义的行为意味着没有保证的行为。在这种特殊情况下,大多数平台无论如何都会计算地址的差异。因此,您通常会在给定平台上看到相同的值。
  • 这是一个非常好的答案!你能详细说明一下第 3 部分吗?
【解决方案2】:

1) 一些编译器确实会针对格式错误的printf 参数发出警告,但作为可变参数函数,运行时无法检查参数是否属于格式字符串指定的类型。当函数尝试将此类参数转换为不正确的类型时,任何不匹配都会发出 未定义的行为

2)您说结果应该是-4,但这是不正确的。只有数组才能保证其指针连续对齐。您不能假设c2 位于(&c1 + 1)

3) (int)&c1 正在将c1 的地址转换为int。通常,这又是未定义的行为,因为您不知道 int 大到足以容纳指针地址值。 (int 可能是 64 位芯片组上的 32 位)。您应该使用intptr_t 代替int

【讨论】:

  • 我认为反对票是错误的。这其实是一个很好的答案。
  • ... 除了第一部分不正确(我不是反对者)。
  • 好的:现在好多了。感谢 cmets 的帮助。
【解决方案3】:

1) void* 只不过是一个地址。地址是一个数字(长)。在那里,地址被隐式转换为 int。

2) 在内存中,您的变量的存储顺序与存储顺序不同 你的代码;)。此外,出于同样的原因:

int a[2];
a[0] = 3;
*(a + 1) = 5; // same that "a[1] = 5;"

此代码将在第二种情况下输入“5”。因为它实际上会这样做:

*(a + 1 *sizeof(*a)) = 5; 

3) 十六进制是数字表示。它可以存储在 int 中!示例:

int a = 0xFF;
printf("%d\n", a); // print 255

希望我已经回答了你的问题。

【讨论】:

  • 第一部分是错误的。区别不是void *。它是一个整数。
【解决方案4】:

这里有多种未定义行为的情况。

如果我们查看 C99 标准部分草案 6.5.6 加法运算符,它会说(强调我的):

当两个指针相减时,两个指针都指向 相同的数组对象,或数组对象的最后一个元素; 结果是两个数组的下标之差 元素。 结果的大小是实现定义的,它的 type(有符号整数类型)是在 中定义的 ptrdiff_t 标题。如果结果在该类型的对象中不可表示, 行为未定义。

虽然,你所拥有的是未定义的行为,因为指针不指向同一个数组的元素。

printf 用于ptrdiff_t 时,正确的格式说明符应该是%td,这给了我们第二种未定义行为的情况,因为您指定了不正确的格式说明符。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-10-18
    • 2019-06-29
    • 2014-09-04
    • 2021-06-25
    • 2021-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多