c \ c ++中存储COM的VT_DECIMAL的正确类型是什么?

时间:2015-10-28 16:41:36

标签: c++ com decimal ado

我正在尝试为ADO编写一个包装器。

DECIMAL类型为COM VARIANT时,VARIANTVT_DECIMAL可以使用的一种类型。

我正在尝试将其置于c本机数据类型中,并保留变量值。 似乎正确的类型是long double,但我得到“没有合适的转换错误”。

例如:

_variant_t v;
...

if(v.vt == VT_DECIMAL)
{
  double d = (double)v; //this works but I'm afraid can be loss of data...
  long double ld1 = (long double)v; //error: more then one conversion from variant to long double applied.
  long double ld2 = (long double)v.decVal; //error: no suitable conversion function from decimal to long double exist.  
}

所以我的问题是:

  1. 使用double存储所有可能的十进制值是否完全安全?

  2. 如果没有,我怎样才能将小数转换为long double?

  3. 如何将小数转换为字符串? (使用<< operator,sprintf对我也有好处)

5 个答案:

答案 0 :(得分:5)

DECIMAL的内部表示不是双精度浮点值,而是整数而不是符号/缩放选项。如果要初始化DECIMAL部分,则应初始化这些字段 - 96位整数值,缩放,符号,然后获得有效的十进制VARIANT值。

DECIMAL on MSDN

  • scale - 数字的小数位数。有效值为0到28.因此12.345表示为12345,标度为3.
  • sign - 表示标志; 0表示正数,DECIMAL_NEG表示负数。所以-1表示为1,并设置了DECIMAL_NEG位。
  • Hi32 - 数字的高32位。
  • Lo64 - 数字的低64位。这是_int64。

您的问题:

  

使用double存储所有可能的十进制值是否完全安全?

您无法直接初始化为double(例如VT_R8),但您可以初始化为double变体并使用变体转换API转换为VT_DECIMAL。可以对值进行小舍入。

  

如果没有,我怎样才能将小数转换为long double?

     

如何将小数转换为字符串? (使用<<运算符,sprintf对我也有好处)

VariantChangeType可以将decimal变量转换为另一种类型的变体,包括integer,double,string - 您提供要转换的类型。反之亦然,您也可以将不同的东西转换为十进制。

答案 1 :(得分:2)

"安全"并非完全正确的单词,DECIMAL的要点是不会因基本转换而引入舍入错误。计算在基数10而不是基数2中完成。这使得它们缓慢但准确,这是会计师喜欢的那种准确性。他不必追逐十亿分之一的不匹配。

使用_variant_t :: ChangeType()进行转换。通过VT_R8转换为双精度。通过VT_BSTR转换为字符串,即会计师喜欢的字符串。追逐long double没有意义,那个10字节的FPU类型是历史。

答案 2 :(得分:2)

此片段取自http://hackage.haskell.org/package/com-1.2.1/src/cbits/AutoPrimSrc.c

Hackage.org 说:

  

Hackage是Haskell社区的开放式中央包存档   源软件。

但请检查作者权限

void writeVarWord64( unsigned int hi, unsigned int lo, VARIANT* v )
{
   ULONGLONG r;

   r = (ULONGLONG)hi;
   r >>= 32;
   r += (ULONGLONG)lo;

   if (!v) return;
   VariantInit(v);
   v->vt = VT_DECIMAL;
   v->decVal.Lo64  = r;
   v->decVal.Hi32  = 0;
   v->decVal.sign  = 0;
   v->decVal.scale = 0;
}

答案 3 :(得分:1)

如果我正确理解了Microsoft的文档(https://msdn.microsoft.com/en-us/library/cc234586.aspx),则VT_DECIMAL是一个精确的92位整数值,具有固定的比例和精度。在这种情况下,您不能在不丢失float,double或64位整数变量的信息的情况下存储它。

最好的办法是将它存储在128位整数中,如__int128,但我不知道编译器对它的支持程度。我也不确定你是否能够在没有采取一些操作的情况下将其中一个投射到另一个。

答案 4 :(得分:1)

  

使用double存储所有可能的十进制值是否完全安全?

这实际上取决于 safe 的含义。如果你的意思是“是否存在引入某种程度的转换不精确的风险?”,是的,存在风险。内部表示太过不同,无法保证完美转换,并且可能会引入转换噪声。

  

如何将小数转换为long double / a string?

它(再次)取决于你想要对象做什么:

对于没有任何转换不精确的存储,您应该将小数存储为pair<long long,short>形式的缩放整数,其中first保存96位尾数,second保存数字小数点右边的数字。此表示尽可能接近十进制的内部表示,不会引入任何转换不精确,也不会浪费CPU资源进行整数到字符串格式化。

相关问题