我正在调查writev
和readv
并且当我显示内存内容时,我得到了奇怪的数据:
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_t
与int
的宽度相同(通常不是)。
根据标准,“如果任何参数不是相应转换规范的正确类型,则行为未定义”(C2011、7.21.6.1/9、7.21.6.3/2)。这适用于你的电话仔细考虑或试图解释未定义的行为并不是很有用,因为它是未定义的。
我不确定我是否遵循您的预期行为,尤其是在iov[0]
方面。那是一个struct
没有struct
s的转换说明符,如果程序不简单地崩溃,您碰巧得到的任何转换都可能是特定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/