I'm planning to inject a thread into another process and unfortunately I need to write the thread function in raw bytes and can't just compile it in my program and then copy it over. The thread needs to receive a struct and call a function by address passing certain contents of the struct as parameters. Now I'm wondering how I could write this basic code in C/C++ and let it being converted into bytes.
In general you cannot expect a function written in C/C++ to result in a single compact, copyable chunk of object code inside your executable. To achieve that you need to tweak the compiler settings and take the function's address in plain view of the compiler, to make it emit the actual code of the function instead of inlining it. Or use an equivalent compiler directive, like
__declspec(noinline) in VC++.
Also, compilers often call helper functions under the hood even if the source code does not show any explicit function calls. There's things like
__security_check_cookie(), for example, or
Having said that, coding such a function in C/C++ can be done with suitable care and suitable control over compiler options. The advantage is that such code is often much clearer and more readable than (inline) assembly.
One option that works on most platforms is to rip the object code for the function from the object file produced by the compiler. This is a bit involved because it requires parsing the object file format but the meta information allows you to ascertain that the object code chunk is free from naughty calls to hidden functions, and items that need relocation (like imports and variable addresses) are also dealt with in the meta data.
One option that can work for 64-bit executables under Windows is using the RUNTIME_FUNCTION info in the .pdata section. This data allows you to determine the physical size of your function and also to verify that the code for the function is in one continguous chunk and not split into several pieces. Leaf functions are usually not included in the .pdata but calling through a function pointer is sufficient to make your function a non-leaf. You still need to inspect the code to ascertain that it is free from naughtiness, though, until you have gathered enough experience with (and trust in) your compiler.
Injecting a DLL is bound to be a lot easier than all that, though. Not to mention less restrictive and much more powerful.