【问题标题】:What's going on with C++ macro multiplicationC++ 宏乘法发生了什么
【发布时间】:2012-01-20 11:50:52
【问题描述】:
#define MAX 265

std::cout << 0 * MAX << std::endl; //to my surprise, the output is 9 rather than 0

这个 C++ 宏乘法有什么问题?

编辑

以下是完整版。

#include <stdio.h>
#include <string.h>
#include <iostream>

#define NAME_BYTES 256
#define VERSION_BYTES 256
#define SIZE_BYTES 32
#define USED_LOCK_COUNT_BYTES 32
#define LOCK_NAME_BYTES 256
#define LOCK_TYPE_BYTES 1
#define PID_BYTES 4
#define TID_BYTES 4
#define LOCK_BYTES LOCK_NAME_BYTES + LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES 
#define HEADER_BYTES NAME_BYTES + VERSION_BYTES + SIZE_BYTES + USED_LOCK_COUNT_BYTES

int main() {
  std::cout << "LOCK_BYTES: " << LOCK_BYTES << std::endl;
  std::cout << "HEADER_BYTES: " << HEADER_BYTES << std::endl;
  std::cout << "LOCK_BYTES * 0: " << 0 * LOCK_BYTES << std::endl;
}

这是我刚刚得到的结果和编译器信息。

yifeng@yifeng-Precision-WorkStation-T3400:~/Shared-Memory-Solution/examples/IMPL$ g++ -v 使用内置规范。 COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6.1/lto-wrapper 目标:x86_64-linux-gnu 配置:../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.1-9ubuntu3' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++, fortran,objc,obj-c++,go --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr /lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with -sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-plugin --enable-objc-gc --disable-werror --with-arch- 32=i686 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu 线程模型:posix gcc版本4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3)

yifeng@yifeng-Precision-WorkStation-T3400:~/Shared-Memory-Solution/examples/IMPL$ ./a.out LOCK_BYTES: 265 HEADER_BYTES: 576 LOCK_BYTES * 0: 9

编辑:非常感谢你们!!我很高兴我决定发布这个,尽管我得到了很多反对票。学习 MACRO 是多么重要的一课!

【问题讨论】:

    标签: c++ macros multiplication


    【解决方案1】:

    您应该始终在宏定义周围加上括号:

    #define LOCK_BYTES (LOCK_NAME_BYTES + LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES)
    

    否则,代码扩展为:

    cout << 0 * LOCK_NAME_BYTES + LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES
    

    输出LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES的值。

    最好不要使用宏,除非你真的必须这样做。这些更好地表示为常量变量。

    【讨论】:

    • 非常非常非常感谢。我在这上面浪费了很多时间!
    • @TerryLiYifeng:是的,调试宏可能需要很多时间。你最好避免使用它们,除非在极少数情况下常量、函数和模板都不能满足你的需求。
    【解决方案2】:
    std::cout << "LOCK_BYTES * 0: " << 0 * LOCK_BYTES << std::endl;
    

    扩展到

    std::cout << "LOCK_BYTES * 0: " << 0 * LOCK_NAME_BYTES + LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES << std::endl;
    

    又扩展为

    std::cout << "LOCK_BYTES * 0: " << 0 * 256 + 1 + 4 + 4 << std::endl;
    

    并为优先规则添加括号:

    std::cout << "LOCK_BYTES * 0: " << ((((0 * 256) + 1) + 4) + 4) << std::endl;
    

    计算结果为

    std::cout << "LOCK_BYTES * 0: " << 9 << std::endl;
    

    将您的代码更改为

    std::cout << "LOCK_BYTES * 0: " << 0 * (LOCK_BYTES) << std::endl;
    

    或者更好的是,使用const unsigned int 值:

    const unsigned int NAME_BYTES = 256;
    const unsigned int VERSION_BYTES = 256;
    const unsigned int SIZE_BYTES = 32;
    const unsigned int USED_LOCK_COUNT_BYTES = 32;
    const unsigned int LOCK_NAME_BYTES = 256;
    const unsigned int LOCK_TYPE_BYTES = 1;
    const unsigned int PID_BYTES = 4;
    const unsigned int TID_BYTES = 256;
    const unsigned int LOCK_BYTES = LOCK_NAME_BYTES + LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES;
    const unsigned int HEADER_BYTES = NAME_BYTES + VERSION_BYTES + SIZE_BYTES + USED_LOCK_COUNT_BYTES;
    

    嘘!突然之间,你不再有奇怪的问题了。

    【讨论】:

    • +1 用于const 讨论。我还想为所有大写名称奖励 -1。但是我累了,一票就够了...干杯,请不要使用它们全部大写的名称,因为它就像 SHOUTING 并且它也与宏名称的约定相冲突,
    • @Alf:在我的约定中,ALL UPPERCASE NAMES 代表我的代码中的整个程序常量,无论它们是否是宏。 :)
    • 这是 Java 约定,它在 C++ 中效果不佳。 Java 从 C 中得到它,而 Java 人却不理解它。在 C++ 中使用那个非常不合适的约定当然是你的选择,但只要你这样做,并且忽略例如FAQ lite, Bjarne's FAQ, my advice here 等等,你知道或者至少不得不怀疑有一些非常基本的东西你没能理解。干杯,
    • @Alf:我从未用 Java 编写过代码!从一开始到现在,我总是用 C++ 编写代码。而现在,我无法理解的“非常非常基本的东西”是什么?
    • @Alf:C++ 常见问题解答是否建议这样做?
    【解决方案3】:

    我认为你计算错了一点。 不像变量,它们的值在被预处理器编译之前被插入。因此,编译器将看到的是:

     0* LOCK_NAME_BYTES + LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES 
    

    这是:

     0 * 256 + 1 + 4 + 4
    

    根据Order of Operations(C++ 的运算符优先级所依据的),乘法首先发生,因此它将等于 9 而不是 0

    PS 如果您不是为嵌入式系统或 Gameboy Color 等过时的控制台开发(请注意我的 gravatar),我强烈建议您使用 const 关键字而不是 #defines 来处理这类事情。

    【讨论】:

    • 这不是答案,而是评论
    • 我要回答的不是问题。
    • 这并不能证明发布不回答的理由。
    • @DeadMG:有趣的是,另一个“为我工作”的答案得到了支持。这个答案更好:可能是提问者确实误读了控制台字体中的 0。
    • @UncleBens:不是来自我。它可能只收到了这些选票,因为它更早。同样是错误的。它们都不是“答案”,它们毫无价值。
    【解决方案4】:

    问题在于您使用宏。你的

    #define LOCK_BYTES LOCK_NAME_BYTES + LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES
    

    没有按照你的想法做。它的作用是以文本方式将每次出现的LOCK_BYTES 替换为LOCK_NAME_BYTES + LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES。所以

    0 * LOCK_BYTES
    

    扩展到

    0 * LOCK_NAME_BYTES + LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES
    

    这是 C++。 尽可能避免使用宏。我们为此提供了const


    这对我来说很好用:

    #include <iostream>
    
    const int name_bytes = 256;
    const int version_bytes = 256;
    const int size_bytes = 32;
    const int used_lock_count_bytes = 32;
    const int lock_name_bytes = 256;
    const int lock_type_bytes = 1;
    const int pid_bytes = 4;
    const int tid_bytes = 4;
    const int lock_bytes = lock_name_bytes + lock_type_bytes + pid_bytes + tid_bytes;
    const int header_bytes = name_bytes + version_bytes + size_bytes + used_lock_count_bytes;
    
    int main() {
      std::cout << "lock_bytes: " << lock_bytes << std::endl;
      std::cout << "header_bytes: " << header_bytes << std::endl;
      std::cout << "lock_bytes * 0: " << 0 * lock_bytes << std::endl;
    }
    

    你有 a good C++ book 可以学习吗?你应该。

    【讨论】:

      【解决方案5】:

      std::cout &lt;&lt; "LOCK_BYTES * 0: " &lt;&lt; 0 * LOCK_BYTES &lt;&lt; std::endl;

      扩展到

      std::cout &lt;&lt; 0 * LOCK_NAME_BYTES + LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES &lt;&lt; std::endl;

      从基本的操作顺序来看,它不等同于0 * (that whole thing)。始终将表达式括在括号中的宏定义中以避免此类错误 - 请记住,预处理器会扩展宏(或多或少)字面意思

      【讨论】:

        【解决方案6】:

        为了完整性发布:

        const unsigned NAME_BYTES = 256;
        const unsigned VERSION_BYTES = 256;
        const unsigned SIZE_BYTES = 32;
        const unsigned USED_LOCK_COUNT_BYTES = 32;
        const unsigned LOCK_NAME_BYTES = 256;
        const unsigned LOCK_TYPE_BYTES = 1;
        const unsigned PID_BYTES = 4;
        const unsigned TID_BYTES = 4;
        const unsigned LOCK_BYTES = LOCK_NAME_BYTES + LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES;
        const unsigned HEADER_BYTES = NAME_BYTES + VERSION_BYTES + SIZE_BYTES + USED_LOCK_COUNT_BYTES;
        

        宏被扩展,consts 没有。总是更喜欢 const,因为它们是类型安全的并且没有括号问题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-13
          • 1970-01-01
          • 1970-01-01
          • 2013-08-26
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多