存储变量并解除引用它们

时间:2014-06-20 13:05:19

标签: c casting memory-address pointer-arithmetic

基于C

中的以下片段
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然后减去?

4 个答案:

答案 0 :(得分:4)

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

2)由于两个指针没有指向同一个数组,因此差异未定义。可以获得任何价值。

3)是的。但是"十六进制"部分不正确。地址以位/二进制形式存储(如整数一样)。您的计划的解释会有什么变化。这与表示无关(hex / dec / oct /...).

答案 1 :(得分:1)

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

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

  

当减去两个指针时,两个指针都应该指向   相同的数组对象,或者超过数组对象的最后一个元素;   结果是两个数组的下标的差异   元素。 结果的大小是实现定义的,以及它的结果   type(有符号整数类型)是中定义的ptrdiff_t   头。如果结果在该类型的对象中无法表示,   行为未定义。

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

printf ptrdiff_t使用%td时的正确格式说明符将是{{1}},因为您指定的格式说明符不正确,所以会给我们第二种未定义的行为。

答案 2 :(得分:0)

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

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

3)(int)&c1正在将c1的地址转换为int。一般来说,这仍然是未定义的行为,因为您不知道int足以保存指针地址值。 (int可能是64位芯片组上的32位)。您应该使用intptr_t代替int

答案 3 :(得分:0)

1)空虚*只不过是一个地址。地址是一个数字(很长)。在那里,地址被隐式地转换为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

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