sizeof(long) is typically defined by the compiler (subjected to the underlying HW architecture).
sizeof(long*) is subjected to the size of the virtual memory address space on your platform.
For example, with the Visual Studio compiler for 64-bit operating system and x64-based processor:
sizeof(long) == 4 
sizeof(long*) == 8 
Therefore:
- With 
long b = p, only the 4 least significant bytes of p are copied into b 
- With 
*(long*)b, you are potentially attempting to access an invalid memory address 
In this example, if the 4 most significant bytes of p are zero, then "no harm is done". But since it is not guaranteed to be the case, when sizeof(long) != sizeof(long*) this code is generally unsafe.
In addition to that, even if sizeof(long) == sizeof(long*), you should still refrain from using this type of conversions (pointer-to-integer), in order to keep your code portable to other platforms.
UPDATE
Please note that printf("%lld\n", *(long*)b) is also unsafe.
You should basically use "%ld" for long values and "%lld" for long long values.
If sizeof(long) < sizeof(long long), then it may lead to a memory access violation during runtime.