Что происходит с C ++ макро размножением - PullRequest
2 голосов
/ 14 декабря 2011
#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 ++, идти --prefix = / usr --program-суффикс = -4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir = / usr / lib --without-enabled-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 = да --enable-плагин --enable-objc-gc --disable-werror --with-arch-32 = i686 --with-tune = универсальный --enable-check = release --build = x86_64-linux-gnu --host = x86_64-linux-gnu --target = x86_64-linux-gnu Модель потока: posix gcc версия 4.6.1 (Ubuntu / Linaro4.6.1-9ubuntu3)

yifeng @ yifeng-Precision-WorkStation-T3400: ~ / Решение с общей памятью / examples / IMPL $ ./a.out LOCK_BYTES: 265 HEADER_BYTES: 576 LOCK_BYTES * 0: 9

РЕДАКТИРОВАТЬ : Спасибо большое, ребята!Я был очень счастлив, что решил опубликовать это, хотя я получаю так много отрицательных отзывов.Какой урок, чтобы узнать о MACRO!

Ответы [ 6 ]

11 голосов
/ 14 декабря 2011

Вы всегда должны ставить скобки вокруг определений макросов:

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

Еще лучше, не используйте макросы, если это действительно не нужно.Они лучше представлены в виде постоянных переменных.

9 голосов
/ 14 декабря 2011
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;

Huzzah!И вдруг у тебя больше нет странных проблем.

6 голосов
/ 14 декабря 2011

Я думаю, вы немного просчитались. макросы не действуют как переменные, их значения вставляются на место до компиляции препроцессором.Таким образом, то, что будет видеть компилятор:

 0* LOCK_NAME_BYTES + LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES 

, что:

 0 * 256 + 1 + 4 + 4

, что соответствует Порядку операций , для которого приоритет оператора C ++основывается, умножение происходит первым, поэтому оно будет равно 9 , а не 0 .

PS Если вы не разрабатываете для встроенных систем или устаревших консолей, таких как Gameboy Colorобратите внимание на мой граватар), я настоятельно рекомендую вам использовать ключевое слово const вместо #define s для подобных вещей.

5 голосов
/ 14 декабря 2011

Проблема в том, что вы используете макросы.Ваш

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

У вас есть хорошая книга C ++ чему поучиться?Вам следует.

2 голосов
/ 14 декабря 2011

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 голос
/ 14 декабря 2011

Проводка для полноты:

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 нет. Всегда предпочитайте консерванты, так как они безопасны от типа и не имеют проблем с пареном.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...