c++ macros multiplication

Qué está pasando con la multiplicación de macro C++



macros multiplication (6)

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

¿Cuál es el problema con esta macro multiplicación de C ++?

EDITAR :

La siguiente es la versión completa.

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

Este es el resultado que acabo de obtener y la información del compilador.

yifeng @ yifeng-Precision-WorkStation-T3400: ~ / Shared-Memory-Solution / examples / IMPL $ g ++ -v Usando las especificaciones incorporadas. COLLECT_GCC = g ++ COLLECT_LTO_WRAPPER = / usr / lib / gcc / x86_64-linux-gnu / 4.6.1 / lto-wrapper Objetivo: x86_64-linux-gnu Configurado con: ../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 ++ , vaya --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 Modelo de subproceso: posix gcc versión 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

EDITAR : ¡Muchas gracias chicos! He estado muy feliz de haber decidido publicar esto, aunque recibo muchos votos a la baja. ¡Qué lección aprender sobre MACRO!


Creo que has calculado mal un poco. las macros no actúan como variables, sus valores se insertan en su lugar antes de la compilación por el preprocesador. Por lo tanto, lo que verá el compilador es:

0* LOCK_NAME_BYTES + LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES

cual es:

0 * 256 + 1 + 4 + 4

que de acuerdo con el orden de operaciones , en el que se basa la precedencia del operador de C ++, la multiplicación ocurre primero, por lo que será igual a 9 no 0 .

PD: si no está desarrollando sistemas embebidos o consolas obsoletas como Gameboy Color (observe mi gravatar), le recomiendo usar la palabra clave const lugar de #define s para este tipo de cosas.


Publicación para completar:

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;

Las macros se expanden, las const no. Siempre prefiera las constelaciones ya que son de tipo seguro y no tienen problemas de paren.


Siempre debe poner paréntesis alrededor de las definiciones de macro:

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

De lo contrario, el código se expande a:

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

que genera el valor de LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES .

Mejor aún, no use macros a menos que realmente tenga que hacerlo. Estos están mejor representados como variables constantes.


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

se expande a

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

que, desde el orden básico de operaciones, no es equivalente a 0 * (that whole thing) . Siempre encierre entre paréntesis las expresiones dentro de las definiciones de macro para evitar este tipo de error: recuerde que el preprocesador expande las macros (más o menos) literalmente .


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

Se expande a

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

Que a su vez se expande a

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

Y con parens agregados para las reglas de precedencia:

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

Que evalúa a

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

Cambia tu código a

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

O mejor aún, use const unsigned int values:

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;

¡Hurra! Y de repente, ya no tienes problemas extraños.


El problema es que usas macros. Tu

#define LOCK_BYTES LOCK_NAME_BYTES + LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES

no hace lo que piensas Lo que hace es reemplazar textualmente cada LOCK_BYTES de LOCK_BYTES con LOCK_NAME_BYTES + LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES . Asi que

0 * LOCK_BYTES

se expande a

0 * LOCK_NAME_BYTES + LOCK_TYPE_BYTES + PID_BYTES + TID_BYTES

Esto es C ++. Evite las macros siempre que sea posible. Tenemos const para eso.

Esto funciona bien para mí:

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

¿Tienes un buen libro de C ++ para aprender? Debieras.