The only time you need a byte order mark is when the program reading the file does not already know what format it’s in. This often is the case with UTF-16, because it comes in two variants, big-endian and little-endian. UTF-16le is not supposed to be used to save data, but it’s the native format for Windows and therefore a lot of files use it anyway.
I’m not aware of any significant use of UCS-4 to save data files, but it would have the same endianness issue. (In theory, there are even more different byte orders that could apply to it, but the hardware that used them was obsolete long before the encoding was invented.)
UTF-8 has no such variants: there is only one UTF-8 format. However, a few programs, including Microsoft Visual Studio 2008 and 2010, can only detect UTF-8 with a byte order mark and also do not support the /UTF-8
option that later versions have, so there is no way to get that version of the compiler to understand UTF-8 without a BOM at all. Newer versions of MSVC can autodetect UTF-8 with no special flags if it has a BOM, and clang, gcc and icc will work just fine with the BOM, but clang in particular will not understand any encoding but UTF-8. Therefore, for C source files, UTF-8 with a BOM is the lowest common denominator for that collection of compilers.
Other than a few special cases like that, the consensus is that you should save your text files in UTF-8 without a BOM. A lot of other software will not understand a BOM, or will run into trouble if you concatenate multiple files that have BOMs. Furthermore, the different encodings of Unicode are easy to autodetect for real-world documents, and UTF-8 is the default in many contexts.