在我的C程序中,我有一行我正在使用'=='运算符,并且这两个操作数被转换为char,如下所示:
char top_level_domain[sizeof(char) * 128];
...
if((char)top_level_domain[i] == ':'
|| (char)top_level_domain[i] == '/')
这推荐/安全吗?如果没有,我该如何检查数组中某个元素的内容?
编辑:在字符文字
中添加了声明和删除的强制转换答案 0 :(得分:17)
一般情况下,当你可以避免强制转换时,更多是安全有效的,因为它允许编译器执行类型检查。例如,发现错误:
// Let's pretend you forgot or mixed up the type here...
char **top_level_domain;
// ...
if ((char) top_level_domain[i] == (char) ':')
...
或者也许......
char top_level_domain[sizeof(char) * 128];
...
// Whoops! forgot to type [i]
if((char)top_level_domain[i] == ':'
|| (char)top_level_domain == '/')
糟糕!你忘了取消引用指针,你得到了垃圾。编译器将给你一个诊断消息,但由于你使用了强制转换,诊断消息就消失了。
注意:这实际上会在某些编译器上导致诊断消息,因为char
比char *
窄,但如果我们使用的是size_t
而不是char
{1}}然后就没有缩小范围了,但它仍然是一个错误。
在很多情况下,C“整数提升”和“通常的算术转换”可能会导致意外行为。例如,
size_t align_to_16_bytes(size_t x)
{
// return x & ~15u; // WRONG
return x & ~(size_t) 15u; // RIGHT
}
但是,一般情况下,只有在使用宽于int
的类型时,或者当您将至少的有符号和无符号类型混合为{{1}时,它才会导致问题}}
Java和C#等新语言在很大程度上避免了这个问题,只允许扩展隐式转换。
答案 1 :(得分:2)
演员阵容“安全”但没用,而且风格很糟糕。通常在C中,需要一个演员表的任何东西都是最糟糕的样式,更常见的是调用未定义的行为,因此源文件中存在的强制转换是“代码味道” - 表明作者可能做错了,读者需要格外小心寻找错误。
只需删除演员表,您的代码就完全可以了。
答案 2 :(得分:1)
强制转换是编译器的一个显式语句,您希望覆盖该语言为您提供的默认隐式类型转换(或缺少它们的帐户)。一般来说,语言设计者会仔细考虑这些默认的隐式类型转换,并使用 C的类型安全性来工作,而不是反对它。
一个很好的例子是void *
,根据C11第6.5.16.1.1节,它可以隐式地通过赋值转换为“指向任何对象类型的指针”。这意味着您可以不,例如,隐式将其转换为指向函数的指针。这正是你在调用malloc()
时希望它工作的方式 - 例如 - 它必须转换为其他类型的指针,因为你显然无法创建{{1}类型的对象1}},但根本没有意义为函数动态分配内存块。因此,这里默认的隐式类型转换完全符合您的要求 - 让您转换为指向任何对象类型的指针,因为这是整个目的,但如果您尝试转换为其他任何内容,则会大声抱怨。
有些人似乎认为从void
投出回报会使你“明确”回到你想做的事情,但是(1)你永远不会看到那些人做像{{1}这样的事情他们似乎从malloc()
中提出了一个特例;并且(2)它根本不会这样做,因为演员实际明确表示的是你想要覆盖C给你的类型安全和默认转换的事实,当你在这种情况下你真正想做的是要遵守它们。
或者,有时隐式类型转换不会为您提供所需内容,并且需要进行强制转换。明显的例子是整数除法,它总是给你一个int i = 1; double d = (double) i;
。使C 的人可以提供另一个操作符来执行带整数的浮点除法,如果他们愿意,但他们没有,结果是如果你想用两个整数执行除法和整数除法不是你想要的,那么你必须将其中一个转换为浮点类型来覆盖默认行为以实现你想要的。如果整数除法 你想要的特定情况,那么你显然不会施放。
因此,作为一般规则,当C为您提供您想要的结果而不进行投射 - 这是大部分时间 - 不要施放。只有在C的默认行为不能满足您的需求时才会进行投射,并且您愿意明确放弃它为您提供的类型安全性。
答案 3 :(得分:0)
演员阵容不安全,不仅是因为Dietrich Epp所说的编译器类型检查问题,还因为价值范围的减少会导致误报:
int myValue = 'a' + 768; //A number that is not equal to 'a'
assert(myValue != 'a'); //This is true...
assert((char)myValue == 'a'); //...but so is this!
当然,这是因为我构造了myValue以产生这种误报。但是,如果整数被转换为char,那么所有整数的1/256将比较等于特定字符,这是很多可能的误报。如果允许编译器为比较选择整数表示,则不会发生这种情况。