My favourite one HAS to be C !! My main language used to be C++, but I'm not really a fan of the high-level features it offers. It's abstraction adds up to the complexity.
So C++ minus the high-level features is C. And I'm doing Kernel development (contributing to Linux) so I have to use C anyway. And if you know how the hardware works, C makes sense.
C has MANY advantages. For example, you actually know what is going on under the hood, you see when a local variable goes to the program stack (stored in stack frames) and is pointed to by a stack base pointer. Then, maybe you have a struct, you want to dynamically allocate it, you see in your head how the malloc function returns the first byte of the address of the allocated in the heap memory. But maybe you have static/global variables, you see the data section being out of executable code. Knowing how memory works is NECESSARY also for strings and string functions. You can't use neither if you don't know how memory works.(or atleast you can't use them properly)
Also, it is VERY flexible. C can even use the processor's registers. (How cool is that, huh?) You don't have to constatly make copies of a variable/data structure, you just make a pointer and play with the original block of memory. If you want to play with the POINTER of the original memory, you make a pointer to pointer variable (this is useful when you want the original pointer to reference to something else, I've barely used it anywhere, but it's still useful). AND, you can have Assembly in your C code.
With pointers you can also fake a lot of high-level features (only if you need them). For example, in C you can fake OOP. That's how Linux device drivers operate, example :
/*You have to declare those function pointers*/
ssize_t (*device_read) (struct file *, char *, size_t, loff_t *);
ssize_t (*device_write) (struct file *, const char *, size_t, loff_t *);
int (*device_open) (struct inode *, struct file *);
int (*device_release) (struct inode *, struct file *);
/*So that you can assign them here
* And do the job
*/
struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
In Linux device drivers faking OOP in C is quite useful, and is not used only with file operations, there are other examples of C object-orientation in the kernel.
Of course, most of these things I mentioned can be done in C++ as well, but I honestly don't like STL, so I'm sticking with C.