此处的代码用于检查输入是否为“ x”。当它是23u时意味着什么,为什么我们不能只写23。
# define IS_X(a) (((unsigned)a | 32) - 97 == 23u)
答案 0 :(得分:1)
'u'与整数一起使用
使用整数常量,'u'
和'U'
确保常量为unsigned
(或unsigned long
,unsigned long long
(大时) )。
23u表示什么,
# define IS_X(a) (((unsigned)a | 32) - 97 == 23u)
u
使23成为unsigned int 23
,而不是signed int 23
。这样,将至少以unsigned
个数学运算完成比较。
然而,左侧((unsigned)a | 32) - 97
的结果是unsigned
,因此无论如何比较都将是unsigned
。 @Jonathan Leffler
某些编译器/代码检查器将警告比较unsigned
与int
。通过使用u
,双方都是相同的类型,因此不会发出此类警告。
关于编译器是否应警告23
是一个单独的问题。
为什么我们不能只写23。
代码可能会使用23
并冒上述严重警告的危险。
从宏的角度来看,良好的编码习惯是()
使用每个参数:
// # define IS_X(a) (((unsigned)a | 32) - 97 == 23u)
// v-v
#define IS_X(a) (((unsigned)(a) | 32) - 97 == 23u)
答案 1 :(得分:1)
正如chux和Jonathan Leffler所指出的,((unsigned)a | 32) - 97
的结果是无符号的。程序员使用的编译器可能具有非常严格的警告级别,可能抱怨混合了无符号和有符号值的比较。强制后缀为23
的第二个操作数u
的无符号类型可能已删除此警告。
该宏绝对是可疑的:a
应该在扩展中加入括号:
#define IS_X(a) (((unsigned)(a) | 32) - 97 == 23u)
宏可能已经写成((a) == 'x' || (a) == 'X')
,但是在大多数情况下a
会被评估两次,这是程序员希望避免的。
由于此宏仅适用于ASCII,所以我想知道为什么不使用这种简单得多的替代方法:
#define IS_X(a) (((a) | 32) == 'x')
答案 2 :(得分:0)
在您给出的示例中,由于通常的算术转换规则,unsigned int
强制转换传播,因此每个数字都转换为unsigned
。因此,明确地说23是无符号的是没有必要的,而且可以说更难看。
很少需要'u'后缀为整数。我可以考虑使用它有两个原因。
1)如果仅对常量执行多项操作,则有时正是您想要的显式无符号行为。以unsigned int x = 524289 * 4096;
为例,假设32位整数,则计算将溢出带符号的版本,这是未定义的行为,但是如果我们如此unsigned int x = 524289u * 4096u;
对其进行修改,则它将非常适合unsigned int
。它的行为也总是被定义。我们本可以将值抛给一个,但我认为这更清楚。
2)一个字:警告。每当有符号或无符号整数之间存在比较时,常见的编译器和linter警告都会抱怨,使
unsigned x = 3;
/* Do stuff */
if (x > 2) // Comparison of signed and unsigned integers
{
/* Do something */
}
引起警告,这可能导致编译失败,具体取决于构建要求的方式。对于带符号整数也可能会执行警告,因此您的短毛猫可能会抱怨:
int roundup16 (int x)
{
return ((x - 1) | 0xf) + 1;
}
返回x,四舍五入到16的下一个倍数。