以便携方式检索传递给variadic函数的int32_t

Mar*_*ton 9 c type-conversion variadic-functions integer-promotion language-lawyer

7.16.1.1 2描述va_arg如下(强调我的):

如果没有实际的下一个参数,或者type与实际的下一个参数的类型不兼容(根据默认参数提升而提升),则行为是未定义的,除了以下情况:

  • 一种类型是有符号整数类型,另一种类型是相应的无符号整数类型,并且该值可在两种类型中表示;
  • 一种类型是指向void的指针,另一种是指向字符类型的指针.

现在我的理解似乎6.5.2.2(函数调用)与我没有矛盾,虽然我可能错了,默认促销是:

  • charintunsigned(指定实施)
  • signed charint
  • unsigned charunsigned
  • shortint
  • unsigned shortunsigned
  • floatdouble

当你知道传递给它的确切的底层类型时,这一切都很好,花花公子va_list(除了char,因为它的签名是实现指定的,所以AFAIK无法进行便携式检索).

当你期望将类型<stdint.h>传递给你时,它会变得更加复杂va_list.

  • int8_t并且int16_t,通过逻辑极限观察来扣除,保证被提升或已经是类型int.然而,依靠我原来的"逻辑"极限观察是非常可疑的,所以我正在寻求你(以及标准)对这个演绎的确认(我可能会遗漏一些我甚至都不知道的角落情况).
  • 这同样适用于uint8_tuint16_t,除基础类型是unsigned
  • int32_t 可能会也可能不会晋升为int.它可能大于,小于或完全相同int.同样适用于uint32_t但是unsigned.如何移植检索int32_tuint32_t传递给va_list换句话说,如何确定if int32_t(uint32_t)是否已被提升为int(unsigned)?换句话说,如何确定是否应该使用va_arg(va, int)va_arg(va, int32_t)检索int32_t传递给可变参数函数而不在任何平台上调用未定义的行为?
  • 我相信同样的问题对int64_t和有效uint64_t.

这是一个理论上的(仅限标准的)问题,假设存在所有精确宽度类型<stdint.h>.我对"实践中的真实"类型的答案不感兴趣,因为我相信我已经了解它们.

编辑

我想到的一个想法是_Generic用来确定基础类型int32_t.我不确定你到底会怎样使用它.我正在寻找更好(更简单)的解决方案.

n. *_* m. 6

#define IS_INT_OR_PROMOTED(X) _Generic((X)0 + (X)0, int: 1, default: 0)
Run Code Online (Sandbox Code Playgroud)

用法:

int32_t x = IS_INT_OR_PROMOTED(int32_t) ? 
              (int32_t)va_arg(list, int) : 
              va_arg(list, int32_t);
Run Code Online (Sandbox Code Playgroud)

使用我的PC上的gcc,宏返回1 for int8_t,int16_tint32_t,0和for int64_t.

使用gcc-avr(一个16位目标),宏返回1代表int8_tint16_t,0代表int32_tint64_t.

对于long宏,无论是否返回0 sizeof(int)==sizeof(long).

我没有任何64位int的目标,但我不明白为什么它不适用于这样的目标.

我不确定这是否适用于真正的病态实现虽然实际上我很确定它现在可以用于任何符合要求的实现.