Respuesta corta: el operador '!' invierte entre true y false una expresión.
El operador && relaciona dos expresiones booleanas. Si alguna de las dos es false, entonces la expresión "expresion1 && expresion2" valdrá false, pero si las dos expresiones son true, entonces la expresión final será verdadera.
Respuesta larga:
Partimos de
*s1 && *s2 && !(*s1 - *s2)
Analicemos. El operador con menos prioridad en esa expresión es el &&, por lo que por ahora lo dejamos aparte y la dividimos en tres partes:
*s1 // Primera parte
*s2 // Segunda parte
!(*s1 - *s2) // Tercera parte
Vale, entonces, la única expresión que hay es !(*s1 - *s2). Dicha expresión tiene un paréntesis, el operador con más prioridad, por lo que lo evaluamos primero con el ejemplo donde *s1 vale 65, y *s2 vale 66. El paréntesis queda así:
65 - 66
Lo que a su vez equivale a...
-1 //Simplemente restamos
Entonces, ya tenemos el paréntesis. La expresión quedaría:
!(-1)
Lo que hace el operador '!' es cambiar de true a false o viceversa la expresión que tenga a la derecha. Por ejemplo, si tenemos "!(false)", pasaría a "true", y si tenemos "!(true)", pasaría a "false". Pero, ¿y que pasa cuando son números? Si tenemos un número distinto de cero, entonces pasa a ser 0 (por ejemplo, "!(2)" equivale a "0"), y si tiene un "0", entonces pasa a valer "1".
Sabiendo esto, la expresión de antes "!(-1)" quedaría así:
0 // Invertimos
Ya sabemos que la primera parte vale 65. Sabemos que la segunda parte vale 66 y sabemos que la tercera parte vale 0. Entonces, nos quedaría así:
65 && 66 && 0
Las expresiones, normalmente, se evalúan de izquierda a derecha, por lo que primero evaluamos "65 && 66". Lo que hace el operador es lo siguiente:
Valor izquierdo | Valor derecho | Resultado |
0 | 0 | false |
0 | Distinto de 0 | false |
Distinto de 0 | 0 | false |
Distinto de 0 | Distinto de 0 | true |
Entonces, la expresión ÚNICAMENTE valdrá true cuando los dos operandos sean DISTINTOS de 0. En cualquier otro caso, la expresión será false.
Entonces, "65 && 66" pasaría a valer true.
Ahora tenemos la expresión "true && 0". Como ya hemos visto, como hay un operando que vale 0, entonces la expresión es false.
Sé que es largo de leer, pero creo que si se lee con detenimiento, se puede entender perfectamente
______________________________________
PD.: Hubiera sido mejor la expresión
*s1 && *s2 && *s1 == *s2