我正在调查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应该将
但是,运行它时,我会得到以下结果:
test1: IOV: &0x603010, IOV: 0x400d34, IOV_BASE: &0xe, IOV_BASE: 0x603010 IOV_LEN: &0x400d34 IOV_LEN: 0x603018

现在,当在gdb中打印test_string1时,我得到以下值:
(gdb) print iov[0]
$1 = {
  iov_base = 0x400d34,
  iov_len = 14
}

真正奇怪的是iov[0]。根据gdb的说法,iov_len的长度是14个字符(实际上是14个字符);但是程序说它的长度是6303768(十进制)。程序确实会输出正确的长度值,但它不在正确的位置(test_string1)。
你知道为什么会发生这种事吗?

最佳答案

这与readv()writev()函数几乎没有关系,它只与它们都使用的struct iovec类型相切。
必须始终确保传递给printf()的格式字符串中的转换规范与同一调用中传递的其余参数的类型正确匹配。你还没有这么做。%x字段描述符要求相应的参数是具有适当宽度的无符号整数类型(而#标志不会改变这一点)。您的实际参数是astruct iovec *、astruct iovec、avoid **、avoid *、asize_t *和asize_t。对于给定的字段类型,没有一个是正确的,除非最后一个是正确的,如果size_tint的宽度相同(通常不是)。
根据标准,“如果任何参数不是相应转换规范的正确类型,则行为未定义”(C2011、7.21.6.1/9、7.21.6.3/2)。这适用于你的电话仔细考虑或试图解释未定义的行为并不是很有用,因为它是未定义的。
我不确定我是否遵循您的预期行为,尤其是在iov[0]方面。那是一个struct没有structs的转换说明符,如果程序不简单地崩溃,您碰巧得到的任何转换都可能是特定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转换说明符用于打印指针(tovoid)。最后一个转换说明符中的z宽度说明符表示参数是size_t的宽度(实际上,该参数正好是size_t)。你不能打印struct本身,所以我省略了它。我插入了强制转换以将指针参数转换为void *类型。所有指针都可以转换为这种类型,而不会丢失信息,而且它是一个特定的void *说明符必须对应的%p

关于c - 在iov(writev)中打包奇怪?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36988645/

10-09 03:58