c# __crt_va_arg有什么作用?

slmsl1lt  于 2023-09-28  发布在  C#
关注(0)|答案(1)|浏览(242)

我使用的是一个叫做LibTIFF的库,它应该可以加载TIFF文件。无论如何,当我打开一个图像并试图获取图像宽度时,它突然开始抛出访问冲突错误:

TIFFDirectory *td = &tif->tif_dir; // 'td' is the image

'td'是图像,我已经检查了调试器中的字段,它们都很好,如果我返回td->td_imagewide,那么就没有问题。问题来自以下代码行,它没有返回td->td_imagewide,而是这样做:

*va_arg(ap, uint16_t *) = td->td_imagewidth;

...其中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_imagewide,但它做到了这一点。它有什么用?这个函数的签名是:

static int _TIFFVGetField(TIFF *tif, uint32_t tag, va_list ap)

编辑:我发现了问题,我应该传入的变量参数是一个指向要填充的值的指针。结果是被调用的函数解引用了我没有传入的东西。

nwwlzxa7

nwwlzxa71#

很明显,函数期望(在变量数量的某个位置)一个指向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会发生什么。variadic的要点是:我们需要一种方法来知道参数的数量和类型。
除了在您的示例中,它稍微复杂一点,因为工作不是由可变参数函数直接完成,而是由子函数完成

#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);

相关问题