Eu não entendo C++, o que esse "if" pede?

Esse é um pseudocódigo, obtido com engenharia reversa. Essa variável ecx0 é um ponteiro para um objeto na memória. Esses +32, +1808, etc são os deslocamentos. Porém, tem umas coisas que são específicas da linguagem c e eu não entendo. O que é esse 0x3FFu? e esse 0x190? Eu sei que são referência a valores na memória, mas eu não entendo essa identação do c. Esse “&” antes do 0x3FFu faz o que?

    if ( (*(_WORD *)(ecx0 + 32) & 0x3FFu) < 0x190 && *(_DWORD *)(ecx0 + 1808) == 55 )
    {
      CPed::GiveDelayedWeapon((CPed *)ecx0, WEAPON_PISTOL, 50);
      v4 = CWeaponInfo::GetWeaponInfo(WEAPON_PISTOL, 1);
      CPed::SetCurrentWeapon((CPed *)v1, v4->nSlot);
    }

É o operador E aritmético.

1 curtida

Mas esse & 0x3FFu ta fazendo o que ali? Multiplicando com o “ecx0 + 32”?

Ele está fazendo a operação E aritmética do valor (ecx0 + 32) com o valor 1023.

Para entender o resultado, sugiro que faça o cálculo no papel, utilizando os valores em base binária.

Tabela verdade do operador E:

0  E  0  =  0
0  E  1  =  0
1  E  0  =  0
1  E  1  =  1
1 curtida

Então ele é apenas um E? & e && em C++ fazem a mesma coisa?
E aquele u depois do 3FF. O que ele faz?

E aritmético? Existe mesmo esse termo? Sinceramente desconheço a terminologia “e aritmético”.
Até onde eu sei & é o operador E lógico bit a bit (bitwise) enquanto && é um operador lógico E.

Em C++ vc até pode entender que eles fazem a “mesma coisa” se estiver lidando com valores lógicos, mas internamente não e o resultado nem sempre é o mesmo por causa do tipo. O resultado do operador & é um valor de um tipo compatível baseado nos dois operandos. Dá uma olhada. Estou representando os inteiros e os booleans usando oito bits, mas os inteiros por exemplo, na maioria das implementações, possuem 32 bits. Em C e em C++ qualquer tipo que contenha um valor diferente de zero é considerado como um valor verdadeiro, enquanto, se o valor for igual a zero, é considerado falso.

#include <iostream>

using namespace std;

int main() {

    int a = 1;      // 00000001
    int b = 3;      // 00000011

    int c = a + b;  // 00000001 +
                    // 00000011
                    // --------
                    // 00000100  (4)

    int d = a & b;  // 00000001 &
                    // 00000011
                    // --------
                    // 00000001  (1)

    cout << "c: " << c << endl;
    cout << "d: " << d << endl;

    // resulta em true
    if ( a && b ) {
        cout << "a && b => verdadeiro" << endl;
    }

    // resulta em um valor diferente de zero
    if ( a & b ) {
        cout << "a & b => verdadeiro" << endl;
    }

    // agora veja...
    a = 1;      // 00000001
    b = 2;      // 00000010

    c = a + b;  // 00000001 +
                // 00000010
                // --------
                // 00000011  (3)

    d = a & b;  // 00000001 &
                // 00000010
                // --------
                // 00000000  (0)

    cout << "c: " << c << endl;
    cout << "d: " << d << endl;

    // resulta em true
    if ( a && b ) {
        cout << "a && b => verdadeiro" << endl;
    }

    // resulta em um valor igual a zero
    if ( a & b ) {
        cout << "a & b => verdadeiro" << endl;
    }

    // agora veja com valores lógicos
    bool ba = true;       // 00000001
    bool bb = false;      // 00000000

    bool bc1 = ba && ba;  // 00000001
    bool bd1 = ba && bb;  // 00000000
    bool be1 = bb && bb;  // 00000000

    bool bc2 = ba & ba;   // 00000001
    bool bd2 = ba & bb;   // 00000000
    bool be2 = bb & bb;   // 00000000

    int bc3 = ba + ba;    // 00000010
    int bd3 = ba + bb;    // 00000001
    int be3 = bb + bb;    // 00000000

    cout << "bc1: " << bc1 << endl;
    cout << "bd1: " << bd1 << endl;
    cout << "be1: " << be1 << endl;

    cout << "bc2: " << bc2 << endl;
    cout << "bd2: " << bd2 << endl;
    cout << "be2: " << be2 << endl;

    cout << "bc3: " << bc3 << endl;
    cout << "bd3: " << bd3 << endl;
    cout << "be3: " << be3 << endl;

    if ( ba && ba ) {
        cout << "ba && ba => verdadeiro" << endl;
    }

    if ( ba && bb ) {
        cout << "ba && ba => verdadeiro" << endl;
    }

    if ( bb && bb ) {
        cout << "bb && bb => verdadeiro" << endl;
    }

    if ( ba & ba ) {
        cout << "ba & ba => verdadeiro" << endl;
    }

    if ( ba & bb ) {
        cout << "ba & ba => verdadeiro" << endl;
    }

    if ( bb & bb ) {
        cout << "bb & bb => verdadeiro" << endl;
    }

    if ( ba + ba ) {
        cout << "ba + ba => verdadeiro (dif. de zero)" << endl;
    }

    if ( ba + bb ) {
        cout << "ba + ba => verdadeiro (dif. de zero)" << endl;
    }

    if ( bb + bb ) {
        cout << "bb + bb => verdadeiro (dif. de zero)" << endl;
    }

    return 0;

}

Complementando. Em Java por exemplo, quando & é usado em uma expressão booleana ele é tratado como o operador & lógico sem curto-circuito, enquanto o && é o E lógico com curto-circuito. Em uma expressão envolvendo outros tipos, & atua como E lógico bit a bit. Veja o exemplo abaixo:

public static void main( String[] args ) {
    
    int a = 1;
    int b = 2;
    int c = 3;
    int d = 0;
    
    // OU lógico com curto-circuito.
    // aqui, a primeira subexpressão relacional a < b
    // resulta em verdadeiro, então o lado direito da
    // expressão lógica não é avaliado, pois
    // basta o lado esquerdo ser verdadeiro para que essa
    // expressão seja verdadeira, pois foi usado um OU
    // dai o nome curto-circuito
    if ( a < b || ( d = 7 ) < c ) {
        System.out.println( "primeiro if" );
    }
    
    System.out.println( "d: " + d );
    
    // OU lógico sem curto-circuito.
    // veja que aqui temos praticamente a mesma expressão,
    // mudando o operador lógico para um OU sem curto-circuito.
    // nesse caso, mesmo o lado esquerdo resultando em verdadeiro,
    // o lado direito será avaliado, atribuindo 7 em d e resultando
    // em falso quando o valor 7 de d for comparado com o 3 em c
    if ( a < b | ( d = 7 ) < c ) {
        System.out.println( "segundo if" );
    }
    
    System.out.println( "d: " + d );
    
}

Assim como em Java e pelas características que expliquei na primeira listagem, tanto & como | podem ser usados em C e em C++ como operadores lógicos sem curto-circuito.

Para terminar, falando da expressão do if que você apresentou, temos em ordem de execução:

  • (*(_WORD *)(ecx0 + 32) & 0x3FFu) < 0x190 && *(_DWORD *)(ecx0 + 1808) == 55 )
  • (ecx0 + 32): somando 32 com o valor da variável ecx0;
  • (_WORD *)(ecx0 + 32): fazendo o cast/coerção explítica do valor obtido na soma para um ponteiro _WORD (provavelmente um ponteiro para “tipos” de 16 bits);
  • *(_WORD *)(ecx0 + 32): obtém o valor contido no endereço obtido usando o operador de indireção/dereferência *;
  • *(_WORD *)(ecx0 + 32) & 0x3FFu): realizando a operação E bitwise com o valor obtido indiretamente naquele endereço com o valor 3FFu, representado em hexadecimal (prefixo 0x);
  • falta ainda a expressão relacional, *(_WORD *)(ecx0 + 32) & 0x3FFu) < 0x190: verifica-se se o valor obtido é menor que 0x190;
  • do lado direito, *(_DWORD *)(ecx0 + 1808) == 55: soma o valor de ecx0 com 1808, faz cast para um ponteiro _DWORD (32 bits provavelmente) e obtem o valor contido no endereço usando *.
  • finalmente, o && é aplicado.
2 curtidas

entendi, vlw

Adicionei várias observações caso seja do seu interesse.

1 curtida