Yes the compiler/linker can sometimes do some magic, such as removing "dead" code (code that is never used in the program) and quite a few other optimizations as well depending on the options you use to compile the code. Also "release" builds are often smaller that "debug" builds because of the lack of debugging symbols in the "release" builds.
it does not generally compress anything. It can re-use identical chunks of code or data (constants for example) so that it only has 1 copy of them instead of several, but that is about the extent of compression. It does not run any sort of zip like compression over anything. Some OS *disk systems* have compression over the whole disk or one folder or even 1 file, but that is outside the compiler. If you have that on in your coding area, you can get some really small files. Both windows and most common unix executable files are full of redundant and useless junk ... windows has a whole slew of just total garbage in the executable if it is GUI enabled... it even has strings and such to print "this program cannot be run on ms dos" if you happen to copy your program to a 30 year old PC by mistake.