__crt_va_arg 做什么?

问题描述 投票:0回答:1

我正在使用这个名为 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)

编辑:我发现了问题,我应该传入的变量参数是指向要填充的值的指针。事实证明,被调用的函数取消引用了我没有传入的内容。

c macros
1个回答
0
投票

显然,函数期望(在可变数量参数的某个位置)指向

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);
© www.soinside.com 2019 - 2024. All rights reserved.