在iov(writev)中奇怪的打包?

时间:2016-05-02 17:57:59

标签: c io printf

我正在调查writevreadv,当我显示内存内容时,我收到了奇怪的数据:

struct iovec *iov = malloc(sizeof(struct iovec) * 3);
iov[0].iov_base = test_string1;
iov[0].iov_len  = strlen(test_string1);
printf("test1: IOV: &%#x, IOV: %#x, IOV_BASE: &%#x, IOV_BASE: %#x IOV_LEN: &%#x IOV_LEN: %#x\n",
&iov[0], iov[0], &iov[0].iov_base, iov[0].iov_base, &iov[0].iov_len, iov[0].iov_len);

我期待着:

  • IOV&列出了IOV
  • 的位置
  • IOV将值存储。
  • IOV_BASE&应该放置IOV_BASE
  • 的位置
  • IOV_BASE应该放置test_string1
  • 的位置
  • IOV_LEN&应该放置IOV_LEN
  • 的位置
  • IOV_LEN应该加上test_string1
  • 的长度

然而,在运行它时,我得到了这些结果:

test1: IOV: &0x603010, IOV: 0x400d34, IOV_BASE: &0xe, IOV_BASE: 0x603010 IOV_LEN: &0x400d34 IOV_LEN: 0x603018

现在,在gdb中打印iov[0]时,我会得到以下值:

(gdb) print iov[0]
$1 = {
  iov_base = 0x400d34, 
  iov_len = 14
}

真正奇怪的是iov_len。根据gdb,test_string1的长度是14个字符(它是);但是,程序说它的长度是6303768(十进制)。该程序确实吐出了正确的长度值,但它不在正确的位置(IOV_BASE)。

关于为什么会发生这种事情的任何想法?

1 个答案:

答案 0 :(得分:0)

这与readv()writev()函数几乎没有任何关系,它只与它们都使用的struct iovec类型相切。

您必须始终确保传递给printf()的格式字符串中的转换规范与同一调用中传递的其余参数的类型正确匹配。你还没有这样做。 %x字段描述符要求相应的参数是适当宽度的无符号整数类型(并且#标志不会改变这一点)。您的实际参数是struct iovec *struct iovecvoid **void *size_t *size_t对于给定的字段类型是正确的,但如果size_tint的宽度相同(通常不是),则最后一个是正确的。 / p>

根据标准,“如果任何参数不是相应转换规范的正确类型,则行为未定义”(C2011,7.21.6.1 / 9,7.21.6.3 / 2)。这适用于您的电话。

指出未定义的行为,或者试图解释未定义的行为并不是很有用。

我不确定我是否遵循了您的预期行为,尤其是iov[0]。那是structstruct没有转换说明符,如果程序不是简单地崩溃,你碰巧得到的任何转换都可能是你特定的C实现的特殊性,也可能是你的程序的特殊性,也许是甚至月亮的阶段(参见“未定义的行为”)。

您可以尝试打印有关struct iovec的详细信息:

printf("test1: IOV &: %p, IOV_BASE &: %p, IOV_BASE: %p, IOV_LEN &: %p, IOV_LEN: %#zx\n",
        (void *) &iov[0], (void *) &iov[0].iov_base, iov[0].iov_base,
        (void *) &iov[0].iov_len, iov[0].iov_len);

%p转换说明符用于打印指针(void)。最后一个转换说明符中的z width-specifier表示该参数是size_t的宽度(该参数实际上恰好是size_t)。你无法打印struct本身,所以我省略了它。我插入了强制转换,将指针参数转换为void *类型。所有指针都可以转换为此类型而不会丢失信息,并且void *说明符必须与%p对应。