【问题标题】:Difference between two unsigned long representations两个无符号长表示之间的区别
【发布时间】:2018-09-26 07:27:53
【问题描述】:

在常量上使用文字后缀有什么区别:

#define MY_LONG 0x1UL

并转换一个常量:

#define MY_LONG (unsigned long)0x1

什么时候选择前者,什么时候选择后者?

【问题讨论】:

    标签: c


    【解决方案1】:

    在常量上使用文字后缀:...和强制转换常量:有什么区别?

    1. 这取决于使用情况。

    让我们尝试使用 2 个定义作为预处理器控制。预处理器数学不理解各种类型的宽度。作为令牌处理的一部分:

    出于此令牌转换和评估的目的,所有有符号整数类型和所有无符号整数类型的行为就像它们分别具有与 intmax_tuintmax_t 类型相同的表示形式... C11dr §6.10。 1 4

    #define MY_LONG1  0x123456789UL
    #define MY_LONG2  (unsigned long)0x123456789
    
    int main(void) {
    #if MY_LONG1 == 0x123456789u
      puts("MY_LONG1 == 0x123456789u");
    #endif
    #if MY_LONG2 == 0x123456789u
      puts("MY_LONG2 == 0x123456789u");
    #endif
    }
    

    #if MY_LONG2 == 0x123456789u 生成 compiler error

    error: missing binary operator before token "long"
     #define MY_LONG2  (unsigned long)0x123456789
    

    注意:L 对预处理没有任何作用。
    注意:U 确实起到了预处理的作用。

    1. 否则取决于常量的值。

    值为1,没有区别。

    但如果值超过ULONG_MAX,(例如:32 位),则下面是unsigned long longU 确保某些无符号 类型,L 确保至少 long

    #define MY_LONG  0x123456789UL
    

    强制转换可以改变值。在下面的这种情况下,值变为 0x23456789 并键入 unsigned long

    #define MY_LONG  (unsigned long)0x123456789
    

    什么时候选择前者,什么时候选择后者?

    L 微调类型至少为 long,强制转换强制类型为 long

    MY_LONG 应至少为long 或该值较小时使用L,在long [-2147483647 ... 2147483647] 的最小 范围内 p>

    如果宏可以与预处理一起使用,请不要使用强制转换。

    否则使用强制转换(long) 来强制执行long。 IMO,这很少是目标。一个例外是常量必须是unsigned long 而不管它的值。

    // Works well if unsigned long is 64-bit or less
    #define MY_ULONG_EVERY_OTHER_BIT  ((unsigned long) 0xAAAAAAAAAAAAAAAAu)
    

    注意:一般来说,我避免在常量中使用L,而是让实现来确定类型。

    以下将是适合unsigned, unsigned long , unsigned long long 的最窄类型。附加 L 将适合最窄的 unsigned long, unsigned long long

    #define MY_BIGU  0x123456789u
    

    OP 的定义存在一个微妙的问题。

    #define MY_LONG  (unsigned long)0x1
    

    应该是下面的,以确保紧密结合。

    #define MY_LONG  ((unsigned long)0x1)
    

    只有少数运算符具有更高的优先级,可能会弄乱代码。病态的例如:MY_LONG[a] 将是 (unsigned long)(0x1[a]) 而不是 ((unsigned long)0x1)[a],但仍然是用 () 包围宏的好习惯,除非评估问题的可能性为零。

    【讨论】:

      【解决方案2】:

      没有实际区别,这些是 100% 等效的。

      唯一形式上的区别是UL 是整数常量的一部分,而强制类型转换可以放在任何表达式之前,包括运行时计算的表达式。

      UL 的主要原因是在重要的地方强制使用整数常量类型。它通常比演员表更具可读性。示例:1UL << n(unsigned long)1 << n

      另一方面,强制转换具有更广泛的用途,因为它们不仅可用于在编译时强制类型,还可以在运行时触发类型转换。

      【讨论】:

      • 那么有理由同时使用 C 语言吗?
      • @user2162550:是的,Lundin 表示;铸造更多的是运行时的事情;非常非正式的说法。
      • @user2162550 我在答案中添加了一些解释。基本上你是在问为什么你的工具箱里必须有螺丝刀和锤子,当你可以用锤子敲下螺丝时。结果并不漂亮,如果您不小心,可能会出现问题。
      【解决方案3】:

      绝对没有区别。两者都是具有相同值和类型的编译时可评估常量表达式,尽管将第二个版本写为((unsigned long)0x1) 可能是明智之举。

      我个人会选择第一个,因为它更清晰;至少在我看来,演员表是 run-time 运算符,而不是 compile-time 运算符。

      【讨论】:

      • 如果没有区别,为什么我们同时拥有它们?
      • @user2162550:因为 C 语言很灵活。在某些情况下,两种不同的构造会收敛到同一事物,例如上述情况。您可以在for 循环甚至switch 块中提出类似的批评。
      • @Bathsheba “你可以在 for 循环甚至 switch 块中提出类似的批评。”是的!! gotoftw! ;-p
      • 请注意,chux 的回答表明不同。
      • @Bob__ 仅在用法中。但我在这里也做了改变,在我看来,Chux 的答案是迄今为止最好的答案。我要赞成它。感谢您 ping 我。
      【解决方案4】:

      两者之间几乎没有区别:它们都是常量表达式,值为1,类型为unsigned long

      一个显着的区别是你可以使用0x1UL作为预处理器测试表达式的一部分,但你不能使用(unsigned long)1

      #include <stdio.h>
      #if 0x1UL
      int main() {
          return 0;
      }
      #else
      #error 0x1UL should be true
      #endif
      

      【讨论】:

        【解决方案5】:

        从技术上讲,有一种方法可以区分它们,但你真的必须非常努力:

        char a [10];
        printf( "size is %zu\n", sizeof(MY_LONG [a]) );
        

        在上面的示例中,文字 (0x1UL) 版本将让数组以 unsigned long 文字作为索引,产生 1,因为它是 sizeof(char)。转换版本将使数组以int 文字作为索引,然后将生成的字符转换为unsigned long,然后再将其传递给sizeof()sizeof(unsigned long) 通常是 8

        这是因为索引运算符 [] 的排名高于强制转换运算符 ()

        【讨论】:

          猜你喜欢
          • 2011-11-02
          • 1970-01-01
          • 1970-01-01
          • 2011-05-19
          • 1970-01-01
          • 2011-09-06
          • 2013-07-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多