首页 文章

C宏乘法发生了什么

提问于
浏览
2
#define MAX 265

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

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

EDIT

以下是完整版本 .

#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

EDIT :非常感谢你们!我很高兴我决定发布这个,虽然我得到了这么多的downvotes . 关于MACRO,需要学到多少教训!

6 回答

  • 5

    你应该总是在宏定义周围加上括号:

    #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 的值 .

    更好的是,除非你真的需要,否则不要使用宏 . 这些更好地表示为常量变量 .

  • 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;
    

    并为优先规则增加了一些parens:

    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;
    

    好哇!突然间,你不再有奇怪的问题了 .

  • 11

    我觉得你算错了一点 . macros 不像变量那样,它们的值在预处理器编译之前插入到它们的位置 . 因此,编译器将看到的是:

    0* LOCK_NAME_BYTES + LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES
    

    这是:

    0 * 256 + 1 + 4 + 4
    

    根据Order of Operations,C的运算符优先级所基于的,乘法首先发生,所以它将等于 9 而不是 0 .

    P.S如果你不是为嵌入式系统或过时的游戏机开发,比如Gameboy Color(注意我的gravatar),我强烈建议你使用 const 关键字而不是 #define 来做这些事情 .

  • 9

    问题是你使用宏 . 您的

    #define LOCK_BYTES LOCK_NAME_BYTES + LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES
    

    不做你的想法 . 它的作用是用 LOCK_NAME_BYTES + LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES 以文本方式替换 LOCK_BYTES 的每一次出现 . 所以

    0 * LOCK_BYTES
    

    扩展到

    0 * LOCK_NAME_BYTES + LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES
    

    这是C. Avoid macros whenever possible. 我们有 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 要学习吗?你应该 .

  • 6

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

    扩展到

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

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

  • 1

    发布完整性:

    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;
    

    宏扩大了,但是还没有问题 .

相关问题