Есть ли у замены неявного преобразования явным приведением какие-либо побочные эффекты?

Лучше явно приводить, чем просто использовать неявное преобразование?

Например, у меня есть перечисление...

/*This enum represents the various encryption types for wifi. For wifi capable devices, a bitwise & result of all supported encryption types should be returned.*/
typedef enum wifi_encryptionType {
    /*Unknown encryption - default value, and for if wifi standard is ever expanded.*/
    WIFIENCTYPE_UNKNOWN = 0,

    /*No encryption - an open network.*/
    WIFIENCTYPE_NONE = 1,

    /*WEP encryption - all widths.*/
    WIFIENCTYPE_WEP = 2,

    /*WPA 1 with a preshared key using Temporal Key Integrity Protocol.*/
    WIFIENCTYPE_WPA_PSK_TKIP = 4,

    /*WPA 1 with a preshared key using Advanced Encryption Standard via CCMP. */
    WIFIENCTYPE_WPA_PSK_AES = 8,

    /*WPA 2 with a preshared key using Temporal Key Integrity Protocol.*/
    WIFIENCTYPE_WPA2_PSK_TKIP = 16,

    /*WPA 2 with a preshared key using Advanced Encryption Standard via CCMP.*/
    WIFIENCTYPE_WPA2_PSK_AES = 32

} wifi_encryptionType;

Который я использую в структуре.

typedef struct {
    char ssid[32];
    wifi_encryptionType encryption;
    wifi_mode mode;
} WifiNetwork;

и я использую значение поля этой структуры в качестве параметра для вызова функции...

read_uint8(readBuffer, &network.encryption);
//read_uint8 takes a struct pointer containing some buffer info, and a uint8_t pointer.

Я получаю предупреждение.

warning: passing argument 2 of 'read_uint8' from incompatible pointer type
expected 'uint8_t *' but argument is of type 'enum wifi_encryptionType *'

Я понимаю, что означает предупреждение. "Имейте в виду, что чтение uint8_t и положить его в wifi_encryptionType В поле можно поместить значения, которые не соответствуют ни одному из объявленных вами значений. "

Преобразование типов выполняется прямо сейчас.

Лучше сделать это явным приведением? Есть ли какие-либо преимущества в явном приведении актеров к игре или какие-либо недостатки?

2 ответа

Решение

Предупреждение в этом случае не просто придирки к компилятору. Это может потенциально сломаться.

Причина в том, что enum тип может иметь другой размер, чем uint8_t, Стандарт C11 гарантирует только это (раздел 6.7.2.2)

Каждый перечисляемый тип должен быть совместим с char, целочисленный тип со знаком или целочисленный тип без знака.

Если вам не повезло, и enum имеет такое же представление, как, например, intтогда вы будете эффективно передавать указатель на начальный байт int, В системе с прямым порядком байтов этот байт не будет иметь такое же значение, как int, даже если значение будет соответствовать.

Еще одна проблема (которая, вероятно, здесь бы не применялась) - это строгие псевдонимы, что означает, что компилятору разрешено предполагать, что одни и те же данные не доступны как два разных типа. Примером будет иметь int* и float* указать на то же место, записав в это место через int*, а затем читать из него через float*, Строгие правила псевдонимов позволяют оптимизировать код, так как компилятор может предположить, что запись через int* не испортит значение float* указывает на (чтобы его пришлось перезагружать, например, в регистр).

Причина, по которой строгое алиасинг, вероятно, здесь не применим uint8_t на практике почти наверняка unsigned char, для которого компилятор делает исключение. char* (или же unsigned char*) может использоваться для доступа к памяти любого типа объекта. Если бы это не было разрешено, то не было бы никакого безопасного способа выполнить "необработанные" байтовые операции, например, например, memcpy(),

enum (большинство Ликли) является int,

Таким образом, вы передаете адрес int где адрес uint8_t ожидается.

Компилятор говорит вам это:

warning: passing argument 2 of 'read_uint8' from incompatible pointer type expected 'uint8_t *' but argument is of type 'enum wifi_encryptionType *'

Это путь к катастрофе.

Чтобы обойти это, используйте временную промежуточную переменную:

{
  uint8_t tmp = network.encryption;
  read_uint8(readBuffer, &tmp);
  network.encryption = tmp;
}
Другие вопросы по тегам