【问题标题】:Completely different output between 32-bit and 64-bit32位和64位完全不同的输出
【发布时间】:2017-11-30 17:05:03
【问题描述】:

我正在开发聊天客户端和服务器。 我目前在我的服务器中有这一行用于调试目的:

printf("Message for %s:\nTimestamp: %ld, Message: %s, Length: %d\n", args->name, *(int64_t*)(message->data), message->data+8, message->length);

args->name 包含一个char* 到一个普通的以空结尾的字符串,并且消息是一个结构字符串*:

struct string
{
    char* data;
    uint32_t length;
    uint32_t capacity;
};

在这种情况下,前 8 个字节是 posix 时间戳,其余的只是一个以 null 结尾的字符串。

如果我使用 -m64 编译,我会得到以下输出:

Message for some_user:
Timestamp: 1512060499, Message: >Server1@some_user:test, Length: 32

但是使用-m32 编译会产生以下输出:

Message for some_user:
Timestamp: 1512060650, Message: (null), Length: 69823144

现在消息通过包含此行的函数传输到客户端:

write(socket_fd, message->data, message->length)

真正奇怪的是,消息完全没有问题地到达客户端。我在客户端得到完全相同的输出。

我是否以某种方式错误地使用了 printf 函数?

【问题讨论】:

  • "%ld" 用于long,不一定是int64_t。将"%" PRId64int64_t 一起使用。
  • 哇,解决了它,但为什么会破坏我的其他指针?
  • 代码向printf() 谎报了关于longint64_t 的问题,所以它很困惑,尤其是后来发生的事情。
  • 因为在 32 位模式下,您在堆栈上传递了一个 8 字节的值,但 printf 认为它是一个 long(在 ILP32 中为四个字节)然后它会占用您时间戳的高 4 个字节作为指向消息的指针(假设小端,这可能是 0)。然后它将指针作为长度。
  • 因为您将 8 个字节放在 printf 预期为 4 的堆栈上,所以所有剩余的参数都比 printf 预期的堆栈低 4 个字节。

标签: c pointers printf cpu-architecture


【解决方案1】:

使用错误的格式说明符打印是 UB(2 个位置)。

// printf("Message for %s:\nTimestamp: %ld, Message: %s, Length: %d\n", 
//    args->name, *(int64_t*)(message->data), message->data+8, message->length);

#include <inttypes.h>

printf("Message for %s:\nTimestamp: %" PRId64 ", Message: %s, Length: %" PRIu32 "\n", 
    args->name, *(int64_t*)(message->data), message->data+8, message->length);

强制转换和取消引用指向int64_t 的任意对齐指针可能会产生问题。最好复制。

int64_t t64;
memcpy(&t64, message->data, sizeof t64);
printf("Message for %s:\nTimestamp: %" PRId64 ", Message: %s, Length: %" PRIu32 "\n", 
    args->name, t64, message->data+8, message->length);

【讨论】:

  • 当调用者和被调用者不同意传递/寻找的类型时,解释可变参数函数到底出了什么问题:Why va_arg() produce different effects on x86_64 and arm?。在这种情况下,32 位 printf 仅消耗 timestamp 的前半部分,并使用后半部分作为指针。 (little-endian 32 位 x86 的高半部分,这就是为什么它是 0,该平台上 NULL 指针的二进制表示)。
猜你喜欢
  • 1970-01-01
  • 2020-03-21
  • 2015-03-19
  • 1970-01-01
  • 2012-01-06
  • 2013-03-12
  • 2012-10-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多