用显式转换替换隐式转换有任何副作用吗?
Does replacing implicit conversion with explicit casting have any side-effects?
显式转换比隐式转换更好吗?
例如,我有一个枚举...
/*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 *'
我明白警告的意思了。 "Be aware that reading a uint8_t
and putting it into a wifi_encryptionType
field can place values in there that do not map to any of the values you have declared."
类型转换现在隐式完成。
让它显式转换更好吗?显式转换是否有任何好处或任何缺点?
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;
}
这种情况下的警告不仅仅是编译器挑剔。这可能会破坏。
原因是 enum
类型的大小可能与 uint8_t
不同。 C11 标准仅保证(第 6.7.2.2 节)
Each enumerated type shall be compatible with char
, a signed integer type,
or an unsigned integer type.
如果你运气不好,enum
具有与例如相同的表示形式int
,那么您将有效地传递一个指向 int
的初始字节的指针。在大端系统上,该字节的值不会与 int
相同,即使该值适合。
另一个问题(虽然可能不会在这里应用)是严格别名,这意味着允许编译器假设相同的数据不作为两个访问不同种类。一个例子是让 int*
和 float*
指向相同的位置,通过 int*
写入该位置,然后通过 float*
从中读取。严格的别名规则允许代码优化,因为编译器可以假设通过 int*
写入不会弄乱 float*
指向的值(因此它必须重新加载到寄存器中例如)。
严格别名在这里可能不适用的原因是 uint8_t
在实践中几乎可以肯定是 unsigned char
,编译器对此例外。 char*
(或unsigned char*
)可用于访问任何类型对象的内存。如果不允许这样做,那么就没有任何安全的方法可以根据需要进行 "raw" 字节操作,例如memcpy()
.
显式转换比隐式转换更好吗?
例如,我有一个枚举...
/*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 *'
我明白警告的意思了。 "Be aware that reading a uint8_t
and putting it into a wifi_encryptionType
field can place values in there that do not map to any of the values you have declared."
类型转换现在隐式完成。
让它显式转换更好吗?显式转换是否有任何好处或任何缺点?
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;
}
这种情况下的警告不仅仅是编译器挑剔。这可能会破坏。
原因是 enum
类型的大小可能与 uint8_t
不同。 C11 标准仅保证(第 6.7.2.2 节)
Each enumerated type shall be compatible with
char
, a signed integer type, or an unsigned integer type.
如果你运气不好,enum
具有与例如相同的表示形式int
,那么您将有效地传递一个指向 int
的初始字节的指针。在大端系统上,该字节的值不会与 int
相同,即使该值适合。
另一个问题(虽然可能不会在这里应用)是严格别名,这意味着允许编译器假设相同的数据不作为两个访问不同种类。一个例子是让 int*
和 float*
指向相同的位置,通过 int*
写入该位置,然后通过 float*
从中读取。严格的别名规则允许代码优化,因为编译器可以假设通过 int*
写入不会弄乱 float*
指向的值(因此它必须重新加载到寄存器中例如)。
严格别名在这里可能不适用的原因是 uint8_t
在实践中几乎可以肯定是 unsigned char
,编译器对此例外。 char*
(或unsigned char*
)可用于访问任何类型对象的内存。如果不允许这样做,那么就没有任何安全的方法可以根据需要进行 "raw" 字节操作,例如memcpy()
.