Visual C++ 6.0 - 可能的转换数据丢失(警告 C4244)

Visual C++ 6.0 - Possible Conversion Loss of Data (Warning C4244)

我使用的是相当老的编译器,我相信编译器在其警告诊断中犯了一点错误。

    typedef unsigned char uint8_t;          // 8-bit byte
    typedef unsigned int uint32_t;          // 32-bit word (change to "long" for 16-bit machines)
    
    typedef struct _sha256_ctx_t
    {
        uint8_t             data[64];
        uint32_t            data_len;
        unsigned __int64    bit_len;        // unsigned long long
        uint32_t            state[8];
    } sha256_ctx_t;


void crypto_sha256_final(sha256_ctx_t *ctx, uint8_t *digest)
{
    uint32_t i;

    i = ctx->data_len;

    // Append to the padding the total message's length in bits and transform.
    ctx->bit_len += ctx->data_len * 8;
    ctx->data[63] = ctx->bit_len; // LINE 156 IS HERE!
    ctx->data[62] = ctx->bit_len >> 8;
    ctx->data[61] = ctx->bit_len >> 16;
    ctx->data[60] = ctx->bit_len >> 24;
    ctx->data[59] = ctx->bit_len >> 32;
    ctx->data[58] = ctx->bit_len >> 40;
    ctx->data[57] = ctx->bit_len >> 48;
    ctx->data[56] = ctx->bit_len >> 56; // LINE 163 IS HERE!

    local_sha256_transform(ctx, ctx->data);

    // Since this implementation uses little endian byte ordering and SHA uses big endian,
    // reverse all the bytes when copying the final state to the output digest.
    for (i = 0; i < 4; ++i) {
        digest[i]      = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
        digest[i + 4]  = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
        digest[i + 8]  = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
        digest[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
        digest[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
        digest[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
        digest[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
        digest[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
    }
}

该代码导致此错误(从第 156 行到第 163 行):

SHA256.cpp(156) : warning C4244: '=' : conversion from 'unsigned __int64' to 'unsigned char', possible loss of data

我猜这个旧编译器没有意识到将它与 0xFF 相加会将结果缩小到一个字节。有人对如何绕过错误警告有建议吗?

原代码来源:https://programmer.group/61737ba233df9.html

在这种情况下,编译器没有任何问题

ctx->data[63] = ctx->bit_len; // LINE 156 IS HERE!
ctx->data[62] = ctx->bit_len >> 8;
ctx->data[61] = ctx->bit_len >> 16;
ctx->data[60] = ctx->bit_len >> 24;
ctx->data[59] = ctx->bit_len >> 32;
ctx->data[58] = ctx->bit_len >> 40;
ctx->data[57] = ctx->bit_len >> 48;
ctx->data[56] = ctx->bit_len >> 56; // LINE 163 IS HERE!

ctx->bit_len 是 64 位类型,因此显然将其存储到 uint8_t 中是行不通的。在 digest[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; 中的那些行中没有使用 0xFF 的掩码。唯一缺少分析的情况是 ctx->data[56] = ctx->bit_len >> 56,因为结果符合 uint8_t。要获得 LSB,您需要进行显式转换,以便编译器知道您在做什么

ctx->data[62] = uint8_t(ctx->bit_len >> 8);

也就是说,没有必要像那样手动复制,只需使用memcpyntohll。代码不好,使用古老的编译器更糟。现在有很多很好的加密库使用适当的 SIMD 和多线程,比如 OpenSSL

编译器可以足够聪明地检查算术表达式的可能范围(在明显的情况下),如果不检查,该编译器发出警告是非常正确的。这确实是由较新版本的编译器以不同方式处理的。

试试这个治疗方法:将分配的表达式转换为 char