C ++宏乘法发生了什么

时间:2011-12-14 17:31:40

标签: c++ macros multiplication

#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;
}

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

  

翳风@翳风精密工作站-T3400:〜/共享内存基溶液/示例/ IMPL $   g ++ -v使用内置规范。 COLLECT_GCC =克++   COLLECT_LTO_WRAPPER = / usr / lib中/ GCC / x86_64的-Linux的GNU / 4.6.1 / LTO-包装   目标: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)

     

翳风@翳风精密工作站-T3400:〜/共享内存基溶液/示例/ IMPL $   ./a.out LOCK_BYTES:265 HEADER_BYTES:576 LOCK_BYTES * 0:9

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

6 个答案:

答案 0 :(得分:11)

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

#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

的值

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

答案 1 :(得分:9)

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;

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

答案 2 :(得分:6)

我认为你错误估算了一下。 不像变量那样,在预处理器编译之前,它们的值在其位置插入。因此,编译器将看到的是:

 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关键字而不是#define来实现这些类型的的东西。

答案 3 :(得分:5)

问题是您使用宏。你的

#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 可供学习?你应该。

答案 4 :(得分:2)

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)。始终将表达式括在括号内的宏定义中以避免此类错误 - 请记住预处理器扩展宏(或多或少)字面

答案 5 :(得分: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;

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