TL;DR: different level of abstractions. There is really no such thing as an object, there are just 1’s and 0’s and interpretations of them.
The CPU doesn’t know about objects, so the same question would apply for it: how can you you have a compiler for a language with objects, when the CPU it targets doesn’t know about objects? And the answer is the same, objects are an abstracts where data and functions are bound together by a convention/standard and it is this convention/standard that really defines an object. While the standard isn’t defined in C, C is able to create an implementation of this standard.
This is in fact how C++ and Obj-C were first created. C was a good choice for doing this, because of its cross platform support and hardware support. This made it possible to write a C++ compiler that not only ran on many different platforms, it also compiled for the many different platforms.
To go back to the CPU example, the CPU doesn’t even know about strings, it just knows about bytes, typically having a register size of 1, 2, 4 or 8 bytes. How can it deal with strings? Easy, it doesn’t. The compiler has a convention/standard that it imposes on itself. Strings in C are really just null terminated chunks of memory. In Python, a string is a variable sized structure that takes 49 to 80 bytes in memory PLUS the chunks of memory that is the “characters”. But all of this is totally irrelevant to the CPU. A python programs “strings” aren’t going to be C strings even though the program is compiled to C, because when the code is compiled to C it isn’t going to use the C conventions for strings when dealing with python strings, it will use python conventions, executed in C.