【问题标题】:Best way to fix type conversion warnings in c++在 C++ 中修复类型转换警告的最佳方法
【发布时间】:2017-10-17 14:46:03
【问题描述】:

所以,当我收到这样的警告时,我一直不知道该怎么办,所以我想要其他专业程序员的建议。当我收到此类警告(不是错误)时

警告 C4267:“=”:从“size_t”转换为“ULONG”,可能会丢失 数据

(省略其他上下文代码)

wchar_t pszName[CREDUI_MAX_USERNAME_LENGTH + 1] = L"user";
wchar_t pszPwd[CREDUI_MAX_PASSWORD_LENGTH + 1] = L"password";

// ..

COAUTHIDENTITY authIdent;

// ...

memset(&authIdent, 0, sizeof(COAUTHIDENTITY));
authIdent.PasswordLength = wcslen(pszPwd);
authIdent.UserLength = wcslen(pszName);

问题显然是 wcslen() 返回 size_t 而 authIdent.PasswordLength 是 ULONG。处理此类警告的最佳方法是什么?他们希望我使用 winapi 函数来代替 wcslen() 吗?

编辑:感谢大家的所有精彩回复!

【问题讨论】:

  • 将变量类型改为size_t?
  • static_cast<ULONG>(wcslen()) 会照顾它吗?
  • @NathanOliver 这样做需要我编辑 WinAPI 结构/类。很确定那将是最糟糕的事情。

标签: c++ windows types warnings


【解决方案1】:

每个编译器警告都需要根据具体情况进行处理。

由于ULONG 是 32 位无符号数,std::size_t 是 64 位无符号数,因此您会在您的平台上收到此警告。

但鉴于 (1) 您的字符串不太可能比 ULONG 长,并且 (2) 两种无符号类型之间的转换总是 明确定义的,我会做务实的事情并使用static_cast

static_cast<ULONG>(wcslen(pszPwd))

【讨论】:

    【解决方案2】:

    由于您可以合理地相信长度适合您可以安全使用的 ULONG:

    static_cast<ULONG>(wcslen(pszPwd))
    

    否则你可以:

    【讨论】:

    • 您的链接已损坏:/
    【解决方案3】:

    字符串长度最自然的类型是size_t。实际上,字符串的大小将适合ULONGsize_t。尽管如此,这样的任务绝对值得警告。想象一下这个愚蠢的错误:

    ULONG x = 0;
    authIdent.PasswordLength = x - 1;
    

    声称此类错误永远不会发生很容易,但通过提供不易出错的界面来防止此类错误同样容易(这也可以防止丑陋的memset 出现在用户代码中):

    struct my_COAUTHIDENTITY {
        private:
            COAUTHIDENTITY authIdent;
        public: 
            my_COAUTHIDENTITY() {
                memset(&authIdent, 0, sizeof(COAUTHIDENTITY));
            }
            void setPasswd(wstring passwd) {
                ...
                authIdent.PasswordLength = static_cast<ULONG>(passwd.size());
            }
     };
    

    【讨论】:

    • 我应该多久创建一次这样的包装结构/类?每当我不得不使用“丑陋”的代码时,我应该这样做吗?
    • @SaniT404 这完全取决于你的风格和你想投资多少。但是,只有它需要我调用 memset 的事实才足以让我隐藏它,因为当我编写代码时,我不想在访问内存位方面编写代码,而是就代码的真正含义而言是关于(即更高级别的抽象)
    • 很高兴知道。感谢您的帮助!
    【解决方案4】:

    一种方法是提供safe_numeric_cast 函数,该函数在非调试版本中执行未经检查的static_cast,同时在调试版本中检查缩小转换。

    例如

    #include <type_traits>
    #include <limits>
    #include <cassert>
    //#include <boost/stacktrace.hpp>  // enable if you have boost 1.65+
    #include <iostream>
    
    extern void foo(std::size_t);
    
    struct conversion_failure
    {
        void operator()() const
        {
            #ifdef NDEBUG
            // welcome to undefined behaviour - or we could log, throw, etc.
            #else
                std::cerr << "conversion out of bounds" << std::endl;
    //            std::cerr << boost::stacktrace::stacktrace();
                std::exit(100);
            #endif
        }
    };
    
    template<class From, class To, class Enable = void>
    struct safe_cast;
    
    template<class Both> struct safe_cast<Both, Both>
    {
        Both operator()(Both in) const {
            return in;
        }
    };
    
    template<
        class Big, 
        class Small
    > 
    struct safe_cast<Big, Small, std::enable_if_t<(std::numeric_limits<Big>::digits > std::numeric_limits<Small>::digits)>>
    {
        Small operator()(Big from) const {
        using to_limits = std::numeric_limits<Small>;
        assert(from >= Big(to_limits::min()) && from <= Big(to_limits::max()) );
        return Small(from);
        }
    };
    
    template<
        class Small, 
        class Big
    > 
    struct safe_cast<Small, Big, std::enable_if_t<(std::numeric_limits<Big>::digits > std::numeric_limits<Small>::digits)>>
    {
        Big operator()(Small from) const {
            return from;
        }
    };
    
    
    template
    <
        class To, 
        class From
    >
    auto safe_numeric_cast(From&& from)
    -> decltype(auto)
    {
        auto conv = safe_cast<From, To>();
        return conv(from);
    }
    
    int main()
    {
        int x = 10;
    
        auto y = safe_numeric_cast<long long>(x);
        std::cout << y << std::endl;
    
        auto z = safe_numeric_cast<int>(y);
        std::cout << z << std::endl;
    
        // should abort on debug build, UB on release
        auto zz = safe_numeric_cast<int>(std::numeric_limits<long long>::max());
        std::cout << zz << std::endl;
    }
    

    【讨论】:

      猜你喜欢
      • 2021-11-02
      • 1970-01-01
      • 2018-07-19
      • 1970-01-01
      • 2021-03-14
      • 2019-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多