指向C

时间:2015-07-08 19:29:26

标签: c pointers unsigned-integer unsigned-char

我已在C编译并运行以下程序:

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main(int argc, char* argv[]){
  uint8_t data[8] = {0, 1, 2, 3, 4, 5, 6, 7};
  uint32_t* pointer32 = &data[0];
  uint64_t* pointer64 = &data[0];

  printf("%" PRIu64 "\n", *pointer64);
  printf("%" PRIu32 "\n", *(pointer32++));
  printf("%" PRIu32 "\n", *pointer32);

  return 0;
}

并收到以下预期输出:

506097522914230528
50462976
117835012

输出正确,对应于数据的按位解释,作为无符号64位整数和无符号32位整数。 我在运行Ubuntu 14.04的64位机器上试过这个。它是用股票gcc编译器(4.8.4?)编译的。编译器会抛出“从不兼容的指针类型分配”警告(可以安全地忽略它,因为意图进行不兼容的分配)。

这是转换和解释“数据”数组中数据的可靠方法,还是建议手动将每个字节一次一个地复制并移位到临时变量?

3 个答案:

答案 0 :(得分:4)

您违反了aliasing rules。所以,明确的答案是:没有

简单地说:你必须没有指向同一个对象的不同类型的指针。这可能会导致代码损坏,因为编译器实际上假设这不会发生并且可能会优化代码。

只是一个非常强烈的暗示:不要忽视警告。他们是有充分理由的。

最好的方法是将每个元素的数组中的数据正确序列化/反序列化为最终类型。这也可以避免值和任何(可能的)填充的endianess(字节顺序)出现任何问题。

我使用这样的函数:

uint32_t readUInt32(const uint8_t **buffer)
{
    ... // increment buffer accordingly
}

这样,我只需沿着该行传递缓冲区指针,而不必关心调用者的递增。技术实际上是一个迭代器。

答案 1 :(得分:1)

  

编译器会抛出“从不兼容的指针类型分配”警告(可以安全地忽略它,因为意图进行不兼容的分配)。

此警告不能也不应该被忽略,因为指针确实不兼容。这是有问题的原因是数据的解释取决于使用的硬件 - 具体来说,取决于机器的字节顺序。

  

最好是建议手动将每个字节一次一个地复制并移位到临时变量吗?

这种方法与字节顺序无关。或者,您可以使用hton{...}/ ntoh{...}函数族来强制执行字节顺序。

答案 2 :(得分:1)

big-endian机器和little-endian机器之间的行为会有所不同,所以你最好手动复制和移动每个字节。