C ++二进制运算符警告

时间:2018-07-12 10:00:09

标签: c++ binary bitwise-operators

有人可以解释一些奇怪的警告行为吗?

我知道它隐式转换为整数。 但是为什么前两行没问题?使用〜运算符时,编译器开始引发警告。如果要转换为整数,是否还应该在前两行发出警告?

Ubuntu 16.04 g ++ 5.4

#include <cstdint>
using namespace std;

// g++ -std=c++11 -Wall -Wconversion main.cpp -o main

// warning: conversion to ‘uint8_t {aka unsigned char}’ from ‘int’ may alter its value [-Wconversion]

int main()
{
    uint8_t a = 0x00U;
    uint8_t b = 0x01U;

    a = a | b;  // no warning
    a |= b;     // no warning
    a = ~b;     // warning
    a = a | ~b; // warning
    a |= ~b;    // warning
    return 0;
}

3 个答案:

答案 0 :(得分:3)

当算术表达式中包含小于public class SomeHeaderInterceptor implements ClientInterceptor { private static final String FULL_METHOD_NAME = "sayHello"; public static CallOptions.Key<String> someHeader = CallOptions.Key.of("some_header_active", "false"); @Override public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> methodDescriptor, CallOptions callOptions, Channel channel) { return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(channel.newCall(methodDescriptor, callOptions)) { @Override public void start(Listener<RespT> responseListener, Metadata headers) { super.start(new ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT>(responseListener) { @Override public void onHeaders(Metadata headers) { Metadata.Key<String> SAYHELLO_ACTIVE_HEADER = Metadata.Key.of("some_header_active", Metadata.ASCII_STRING_MARSHALLER); if (methodDescriptor.getFullMethodName().equals(FULL_METHOD_NAME)) { if (!headers.containsKey(SAYHELLO_ACTIVE_HEADER)) { LOGGER.logError("some_header activation missing from header: " + headers); } else { callOptions.withOption(someHeader, "true"); Context.current().withValue(Context.key("test"), "testvalue"); } } super.onHeaders(headers); } }, headers); } }; } 的变量或值时,它是implicitly convertedpublic Iterator<String> sayHello() { Iterator<String> stream = blockingStub.sayHello(); // wait for the sayhello active header boolean isActive = Boolean.parseBoolean(blockingStub.getCallOptions().getOption(SomeHeaderInterceptor. someHeader)); System.out.println("the some_header header value is: " + isActive); System.out.println("the context key : " + Context.key("test").get(Context.current())); return stream; } 。对于某些类型,编译器可以进行另一次隐式转换,将其转换回原始类型,但对于另一些类型,则不能不丢失数据。

例如,使用您的无符号字节值int。转换为int后,它将变为0x00。按位补码将其转换为int,在不丢失数据的情况下不能将其转换回无符号字节。

这对于像这样的值尤为不利,因为作为0x00000000的值0xffffffff等于int(请阅读two's complement以了解原因),这可以真的不能干净地转换为 unsigned 字节。

因此,也不要冒溢出的危险(除非有此需要),我建议您使用0xffffffff(或-1)进行所有整数运算。然后不要转换为较小的类型,除非您绝对需要它。

答案 1 :(得分:0)

如果您不想要任何警告,这里有两种可能:

解决方案1:

int main()
{
    uint8_t a = 0x00U;
    uint8_t b = 0x01U;

    a = a | b;
    a |= b;
    a = static_cast<uint8_t>(~b);
    a = a | static_cast<uint8_t>(~b);
    a |= static_cast<uint8_t>(~b);
    return 0;
}

解决方案2:

int main()
{
    uint32_t a = 0x00U;
    uint32_t b = 0x01U;

    a = a | b;
    a |= b;
    a = ~b;
    a = a | ~b;
    a |= ~b;
    return 0;
}

您可能会认为第二个效率较低,因为它使用了较大的数字,这实际上是错误的。在第一种解决方案中,由于operator ~导致的隐式转换为32位数字会消耗一些内存和性能。第二个解决方案实际上应该更有效。通常,如果要使用8位值,则应至少使用uint32_t并使用掩码:

uint32_t value = 0xFFFFFFFF;
uint32_t mask = 0xFFu;

value &= mask; // Now value is 0x000000FF

答案 2 :(得分:0)

编译器很聪明:     uint8_t a = 0x00U;     uint8_t b = 0x01U;

a = a | b;  // no warning
a |= b;     // no warning

给定两个8位值,|不能设置高于8的位。因此,转换回8位时不会丢失任何位。

a|b的结果无论如何都是int,但是编译器也知道它是8位整型int。

~a的结果不是8位整型int-a转换为一个(可能是32位)int,然后将所有位取反(设置高位)。因此,如果将其转换回8位,则会丢失一些设置的高阶位。

在所有这些情况下都是如此:

a = ~b;     // warning
a = a | ~b; // warning
a |= ~b;    // warning

a=~b之后,a==~b不正确。在a=a|~b的情况下,如果我们存储结果auto c=a|~b;,那么a=ca==c之后就不会成立。 |=案例具有类似的观察结果,但会自我修改。