c - 指针地址符合标准的转换

标签 c undefined-behavior standards-compliance

我需要找到最符合标准的方法来获取指针的地址并单独存储其字节(例如,串行传输它们)。

我有以下两个版本,我认为第一个包含未定义的行为,第二个应该只包含根据 C99 定义的行为。但是我的工具告诉我第二个也有未定义的行为。有人可以确认一下吗?如果可能的话,请指出既没有未定义行为也没有实现定义行为的解决方案?

编辑:我将类型从 int 更改为 unsigned long 以帮助找到不依赖于实现的解决方案。我还删除了“16 位宽指针”。

unsigned long a[2];
unsigned char b0, b1, b2, b3;

int main1() {
  unsigned long l = (unsigned long) &(a[0]);
  b0 = (l >> 24) & 0xFF;
  b1 = (l >> 16) & 0xFF;
  b2 = (l >> 8) & 0xFF;
  b3 = l & 0xFF;
  return 0;
}


typedef union { unsigned long* p; char c[sizeof(unsigned long *)]; } u;

int main2() {
  u x;
  x.p = a;
  b0 = x.c[3];
  b1 = x.c[2];
  b2 = x.c[1];
  b3 = x.c[0];
  return 0;
}

编辑 2:添加了对与这些程序有关的 C99 标准的一部分的引用:

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.

这是否意味着不依赖于某些实现定义的行为就不可能读取数组 a 的地址?或者有什么办法可以规避吗?

最佳答案

对于指针,最好使用类型unsigned long(或unsigned long long)。除非有 uintptr_t 数据类型。 为什么 unsigned?因为移位操作只对无符号整数通用。对于已签名的,它取决于平台。

所以如果你想传输地址(不管什么原因,因为地址通常是进程本地的),你可以像下面这样:

/**
 * @param ptr Pointer to serialize
 * @param buf Destination buffer
 * @param be  If 0 - little endian, 1 - big endian encoding
 */
void ptr2buf(const void *ptr, void *buf, int be)
{
    uintptr_t u = (uintptr_t)ptr;
    unsigned char *d = buf;

    if (be)
    {
        /* big endian */
        d += sizeof(t) - 1;

        for (i = 0; i < sizeof(t); ++i)
        {
            *d-- = u & 0xFF;
            u >>= 8;
        }
    }
    else
    {
        /* little endian */

        for (i = 0; i < sizeof(t); ++i)
        {
            *d++ = u & 0xFF;
            u >>= 8;
        }
    }
}

关于c - 指针地址符合标准的转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16689271/

相关文章:

awk - 为什么一些 Linux 发行版默认提供 mawk,尽管它不符合 POSIX 标准?

c - MD5源代码未输出正确值

c - 警告 :initialization from incompatible pointer type

CRC算法实现

c - 取消引用 void**-casted type** 会打破严格的别名吗?

html - XHTML 合规性毫无意义吗?

c - memcpy 到宏中定义的字符串缓冲区

c - 未初始化的 C 结构字段

c - 返回 ;这个语句返回什么?

c++ - main() 真的是 C++ 程序的开始吗?