This is about the way that Solidity byte
types are represented for use in the EVM: byte
types are all left-justified within a 32-byte word, i.e. a single byte
type is left-shited by 31 * 8 = 248 bits before being put on the stack.
In your first example, variable b
is a single-width byte
type so it is put on the stack as 0x2c00000000000000000000000000000000000000000000000000000000000000
. However, 0xf
has no particular type, so it is put on the stack as 0x0f
, which is the same as 0x000000000000000000000000000000000000000000000000000000000000000f
. The logical and
of these is clearly zero.
In your second example, both of the operands to and
are explicitly byte
types, therefore Solidity computes: 0x2c00000000000000000000000000000000000000000000000000000000000000 & 0x0f00000000000000000000000000000000000000000000000000000000000000
, and then it reports the single byte result c
in the Check event (the left-most byte of the result, since that's how byte
s are stored in Solidity).
The Remix IDE debugger is very helpful for stepping through code like this to see what's going on under the hood. If you are going to use some assembly code I highly recommend it - as you can see there are some surprises.