C4244:“+=”:从“std::streamsize”转换为“size_t”,可能丢失数据

Posted

技术标签:

【中文标题】C4244:“+=”:从“std::streamsize”转换为“size_t”,可能丢失数据【英文标题】:C4244: '+=' : conversion from 'std::streamsize' to 'size_t', possible loss of data 【发布时间】:2016-01-06 12:20:05 【问题描述】:

我已将我的 VC++ 项目从 VS2008 迁移到 VS2013,并收到如下警告:

C4244: '+=' : conversion from 'std::streamsize' to 'size_t', possible loss of data.

如何解决这些类型的警告?

【问题讨论】:

warning C4244: 'argument' : conversion from 'time_t' to 'unsigned int', possible loss of data -- C++的可能重复 @rkm_Hodor_king 不是真的。 【参考方案1】:

在 MSVC 2013 中 std::streamsize 是:

typedef _Longlong streamsize;
typedef _LONGLONG _Longlong;
#define _LONGLONG   __int64

size_t 是:

typedef unsigned __int64    size_t;

因此,一个简单的复制案例是:

unsigned __int64 b = 1;
__int64 a = b;

但这不会发出警告 - 所以您可能在某处将 size_t 重新定义为 32 位?

为了清楚起见:

std::streamsize b = 1;
size_t a = 0;
b = a;

也不会发出警告。

【讨论】:

【参考方案2】:

正如c++ reference 中所述,std::streamsize 被定义为signed(强调我的):

std::streamsize 类型是一个有符号整数类型,用于表示在 I/O 操作中传输的字符数或 I/O 缓冲区的大小。它用作std::size_t签名副本,类似于POSIX类型ssize_t

总之,具体的实现好像没有具体说明。

通常,从signed 到具有相同基数的unsigned 类型(例如long)的转换不应发出有关可能丢失数据的警告(除非使用符号指示符)。

这在 Visual Studio C++ 中可能是一个糟糕的实现。

【讨论】:

unsigned int u = (int)-1; 怎么样?你希望u 是什么?你会考虑这种数据丢失吗?编译器应该发出警告吗?【参考方案3】:

这取决于用途。根据cppreference.com,

除了在 std::strstreambuf 的构造函数中,从不使用 std::streamsize 的负值。

所以你可以安全地转换你的签名值。

std::streamsize i;
// ...
size_t u = static_cast<size_t>(i);

但是,在更一般的情况下(与 πάντα ῥεῖ 所写的相反),我认为警告是有效的(即使 gcc 没有吐出类似的警告)。在比较有符号和无符号值时,最好明确您的意思。

您可以强制无符号,例如使用如下代码 sn-p(感谢this question 的一般形式):


#include <iostream>

template <typename T>
typename std::enable_if< std::is_signed<T>::value, typename std::make_unsigned<T>::type >::type
force_unsigned(T u) 
        if (u < 0) 
                throw std::overflow_error("Cannot use negative value as unsigned type");
        
        return static_cast< typename std::make_unsigned<T>::type >(u);


template <typename T>
typename std::enable_if< !std::is_signed<T>::value, T >::type
force_unsigned(T u) 
        return u;


int main() 
  std::cout << force_unsigned((unsigned int)1) << std::endl;
  std::cout << force_unsigned((int)1) << std::endl;
  std::cout << force_unsigned((int)0) << std::endl;
  std::cout << force_unsigned((int)-1) << std::endl;
  return 0;


【讨论】:

以上是关于C4244:“+=”:从“std::streamsize”转换为“size_t”,可能丢失数据的主要内容,如果未能解决你的问题,请参考以下文章

编译器错误 C4244:“正在初始化”:从“__int64”转换为“int”,可能丢失数据

如何为 std::vector 复制或使用隐式缩小转换禁用 Visual Studio 警告 C4244

提升 microsec_time_clock.hpp 警告 C4244

关于数据丢失的警告 c++/c

X86 架构 - 使用 unsigned long long 设置向量大小

nodejs mongoose安装问题