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
Adicionei várias observações caso seja do seu interesse.
1 curtida