捍卫"U"十六进制文字后缀 [英] Defending "U" suffix after Hex literals

查看:272
本文介绍了捍卫"U"十六进制文字后缀的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我和我的同事之间,对于十六进制表示的文字后的U后缀有一些争论.请注意,这不是关于此后缀的含义或其作用的问题.我在这里找到了其中几个主题,但没有找到问题的答案.

There is some debate between my colleague and I about the U suffix after hexadecimally represented literals. Note, this is not a question about the meaning of this suffix or about what it does. I have found several of those topics here, but I have not found an answer to my question.

一些背景信息:

我们正在尝试制定一套我们都同意的规则,从那时起将其用作我们的样式.我们有 2004 Misra C 规则的副本,并决定以此为起点.我们对完全符合Misra C并不感兴趣.我们正在挑选我们认为将最大程度提高效率和健壮性的规则.

We're trying to come to a set of rules that we both agree on, to use that as our style from that point on. We have a copy of the 2004 Misra C rules and decided to use that as a starting point. We're not interested in being fully Misra C compliant; we're cherry picking the rules that we think will most increase efficiency and robustness.

上述准则中的规则10.6规定:

Rule 10.6 from the aforementioned guidelines states:

后缀"U"应应用于所有无符号类型的常量.

A "U" suffix shall be applied to all constants of unsigned type.

我个人认为这是一个好规则.它花费很少的精力,看起来比显式强制转换更好,并且更显式地显示常数的意图.对我而言,将它用于所有无符号竞争者,而不仅仅是数字是有意义的,因为强制规则不会通过允许例外而发生,特别是对于常用的常量表示而言.

I personally think this is a good rule. It takes little effort, looks better than explicit casts and more explicitly shows the intention of a constant. To me it makes sense to use it for all unsigned contants, not just numerics, since enforcing a rule doesn't happen by allowing exceptions, especially for a commonly used representation of constants.

但是,我的同事认为十六进制表示形式不需要后缀.主要是因为我们几乎专门用它来设置微控制器寄存器,而将寄存器设置为十六进制常量时,有符号性并不重要.

My colleague, however, feels that the hexadecimal representation doesn't need the suffix. Mostly because we almost exclusively use it to set micro-controller registers, and signedness doesn't matter when setting registers to hex constants.

我的问题

我的问题不是谁对谁错.这是关于确定是否存在后缀不存在或情况改变手术结果的情况.是否有这样的情况,还是有关连贯性的问题?

My question is not one about who is right or wrong. It is about finding out whether there are cases where the absence or presence of the suffix changes the outcome of an operation. Are there any such cases, or is it a matter of consistency?

进行澄清;特别是关于通过为其分配十六进制值来设置微控制器寄存器的方法.在某些情况下后缀会有所作为吗?我觉得不会.例如,飞思卡尔处理器专家将所有寄存器分配生成为无符号.

for clarification; Specifically about setting micro-controller registers by assigning hexadecimal values to them. Would there be a case where the suffix could make a difference there? I feel like it wouldn't. As an example, the Freescale Processor Expert generates all register assignments as unsigned.

推荐答案

U后缀附加到所有十六进制常量可以使它们变为无符号的,正如您已经提到的那样.当这些常量与带符号的值(尤其是比较)一起用于运算时,这可能会产生不良的副作用.

Appending a U suffix to all hexadecimal constants makes them unsigned as you already mentioned. This may have undesirable side-effects when these constants are used in operations along with signed values, especially comparisons.

这是一个病理示例:

#define MY_INT_MAX  0x7FFFFFFFU   // blindly applying the rule

if (-1 < MY_INT_MAX) {
    printf("OK\n");
} else {
    printf("OOPS!\n");
}

已精确指定了有符号/无符号转换的C规则,但有些违反直觉,因此上述代码的确会显示OOPS.

The C rules for signed/unsigned conversions are precisely specified, but somewhat counter-intuitive so the above code will indeed print OOPS.

MISRA-C规则很精确,因为它指出后缀"U"应应用于所有无符号类型的常量." unsigned "一词具有深远的影响,并且实际上,大多数常量都不应该真正被认为是无符号的.

The MISRA-C rule is precise as it states A "U" suffix shall be applied to all constants of unsigned type. The word unsigned has far reaching consequences and indeed most constants should not really be considered unsigned.

此外,C标准在十进制和十六进制常量之间产生了微妙的差异:

Furthermore, the C Standard makes a subtile difference between decimal and hexadecimal constants:

  • 如果十六进制常量的值可以由无符号整数类型表示,而不是对于int及更大类型的相同大小的有符号整数类型,则将其视为无符号常量.
  • A hexadecimal constant is considered unsigned if its value can be represented by the unsigned integer type and not the signed integer type of the same size for types int and larger.

这意味着在32位2的补码系统上,2147483648longlong long,而0x80000000unsigned int.在这种情况下,添加一个U后缀可能会使此含义更加明确,但是避免潜在问题的真正预防措施是要求编译器完全拒绝带符号/无符号的比较:gcc -Wall -Wextra -Werrorclang -Weverything -Werror是节省生命的方法.

This means that on 32-bit 2's complement systems, 2147483648 is a long or a long long whereas 0x80000000 is an unsigned int. Appending a U suffix may make this more explicit in this case but the real precaution to avoid potential problems is to mandate the compiler to reject signed/unsigned comparisons altogether: gcc -Wall -Wextra -Werror or clang -Weverything -Werror are life savers.

这有多严重:

if (-1 < 0x8000) {
    printf("OK\n");
} else {
    printf("OOPS!\n");
}

上面的代码应在32位系统上打印OK,在16位系统上打印OOPS.更糟的是,看到嵌入式项目使用过时的编译器甚至没有实现此问题的标准语义的情况仍然很普遍.

The above code should print OK on 32-bit systems and OOPS on 16-bit systems. To make things even worse, it is still quite common to see embedded projects use obsolete compilers which do not even implement the Standard semantics for this issue.

对于您的特定问题,专门用于通过赋值设置它们的微处理器寄存器的定义值(假设这些寄存器是内存映射的),根本不需要后缀U.寄存器左值应具有无符号类型,并且十六进制值将根据其值进行带符号或无符号,但是操作将以相同的方式进行.在您的目标体系结构和我见过的任何体系结构上,用于设置带符号号或无符号号的操作码都是相同的.

For your specific question, the defined values for micro-processor registers used specifically to set them via assignment (assuming these registers are memory-mapped), need not have the U suffix at all. The register lvalue should have an unsigned type and the hex value will be signed or unsigned depending on its value, but the operation will proceed the same. The opcode for setting a signed number or an unsigned number is the same on your target architecture and on any architectures I have ever seen.

这篇关于捍卫"U"十六进制文字后缀的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆