我正在使用这个名为 LibTIFF 的库,它应该加载 TIFF 文件。无论如何,当我打开图像并尝试获取图像宽度时,它突然开始抛出访问冲突错误:
TIFFDirectory *td = &tif->tif_dir; // 'td' is the image
'td' 是图像,我已经检查了调试器中的字段,它们都很好,如果我返回 td->td_imagewidth 那么就没有问题。问题来自以下行,它不是返回 td->td_imagewidth 而是这样做:
*va_arg(ap, uint16_t *) = td->td_imagewidth;
... va_arg 是 __crt_va_arg 的定义,而 va_arg 是 __crt_va_arg 的定义:
#define __crt_va_arg(ap, t) \
((sizeof(t) > sizeof(__int64) || (sizeof(t) & (sizeof(t) - 1)) != 0) \
? **(t**)((ap += sizeof(__int64)) - sizeof(__int64)) \
: *(t* )((ap += sizeof(__int64)) - sizeof(__int64)))
我不知道这是做什么的。它只需要返回 td->td_imagewidth 但它这样做了。它有什么作用?哦,这个函数的签名是:
static int _TIFFVGetField(TIFF *tif, uint32_t tag, va_list ap)
编辑:我发现了问题,我应该传入的变量参数是指向要填充的值的指针。事实证明,被调用的函数取消引用了我没有传入的内容。
显然,函数期望(在可变数量参数的某个位置)指向
uint16_t
的指针,并通过写入该指向的变量来执行操作。
有点像如果是的话
static int TIFFGetField(TIFF *tif, uint32_t tag, uint16_t *val){
// bla bla bla (something that deduces that it is imagewidth that is wanted)
*val = td->td_imagewidth;
}
但它是使用可变参数函数来做到这一点的。该可变参数函数 (
TiffGetField
) 本身依赖于一个不是可变参数函数的子函数,但需要 va_list
作为其参数之一(有点像 vprintf
):_TiffVGetField
.
更简单的说明:如果我想创建一个函数来增加所有指针传递给 int 的变量,我可以这样写
#include <stdio.h>
#include <stdarg.h>
void incrAll(int num, ...){
va_list ap;
va_start(ap, num);
for(int i=0; i<num; i++){
* (va_arg(ap, int *)) += 1;
}
}
int main(){
int x=1, y=2, z=3;
incrAll(2, &x, &z);
incrAll(3, &x, &y, &z);
printf("%d %d %d\n", x, y , z);
}
是的,天知道如果传递的指针数量不匹配会发生什么
num
。可变参数的要点是:我们需要一种方法来知道参数的数量和类型。
除了在您的示例中,它有点复杂,因为工作不是由可变参数函数直接完成,而是由子函数完成
#include <stdio.h>
#include <stdarg.h>
void _incrAllV(va_list ap){
* (va_arg(ap, int *)) += 1;
}
void incrAll(int num, ...){
va_list ap;
va_start(ap, num);
for(int i=0; i<num; i++){
_incrAllV(ap);
}
}
int main(){
int x=1, y=2, z=3;
incrAll(2, &x, &z);
incrAll(3, &x, &y, &z);
printf("%d %d %d\n", x, y , z);
}
所以,这只是一个更新指针作为参数传递的变量的函数。但由于它是一个可变参数函数而变得复杂。
你可能应该这样称呼它(或一些变体)
uint16_t w, h;
# Totally speculating on the name of the tags
TiffGetField(tif, TiffTag_Width, &w, TiffTag_Height, &h);