Search code examples
c++cfunctionoperator-overloadingoperators

Are operators in C implemented as functions like C++?


I was reading a tutorial on operator overloading in C++ when I saw this:

In C++, operators are implemented as functions. By using function overloading on the operator functions, you can define your own versions of the operators that work with different data types.

The compiler comes with a built-in version of the plus operator (+) for integer operands -- this function adds integers x and y together and returns an integer result.

Are operators in C also implemented as functions? If not, how are operators implemented in C?

Could it also be that operators being implemented as functions for POD types is something that only certain compilers do?


Solution

  • I've always found it easier to think about operator overloading as being exactly the same as function overloading: the compiler uses the types of the arguments to choose the appropriate overload. For ordinary functions that's straightforward: just look at all the functions with the appropriate name that are in scope, and choose the best match.

    For operator overloading its just as easy, provided you're willing to forget the detail that the compiler itself knows about all those operators. When I see code that uses the + operator I look at the argument types and mentally apply the rules for choosing the best overload. For a really simple example:

    struct S {
    };
    int operator+(S s1, S s2) { return 42; }
    
    S s;
    int x1 = 1 + 1; // uses "builtin" operator+
    int x2 = s + s; // uses user-defined operator+
    

    So, that's easy; it doesn't really matter how you think about what underlies those two + operators. But let's make it a bit more tricky:

    struct T {
        operator S() const { return S(); }
    };
    
    S s;
    T t;
    int x3 = s + t;
    

    Now what? Since there's an S involved in the sum, the compiler looks for + operators that take an S, and it finds the one we defined earlier. And because T can be converted to an S, it can convert the t to an S object and then use operator+(S, S). Easy enough, right?

    Now, instead of having a conversion to S, let's have a conversion to int:

    struct U {
        operator int() { return 42; }
    };
    

    and let's try the analogous code:

    int i = 1;
    U u;
    
    int x4 = i + u;
    

    Having just done the previous example, it's easy to see the analogy for the analysis here: a U can be converted to an int, so the compiler can convert u to an int object and then use operator+(int, int).

    To me that's much simpler than having two categories, builtin types and user-defined types, and two disjoint notions of operators and how to analyze them.

    So, I think of builtin operators as if they were user-defined operators in order to sort out which overload should be called.

    Now, that doesn't mean that the compiler in fact uses function calls for these builtin operators. That could be inefficient; in fact, compilers these days typically generate the code to add two numbers directly, typically as a couple of machine instructions. But that's not required; a conforming implementation could actually have a function to add two int values and call that when it sees something like 1 + 1. And sometimes that makes sense. Consider an 8-bit processor and the code for adding two long long values. Yes, it could be done inline. But implementing an 8-byte addition in a function and calling it whenever it's needed could result in smaller code; for an embedded system that can be important.

    The point here is that for understanding what an expression means, it doesn't matter whether + produces a function call or some inline code. The meaning of the code doesn't depend on how it's implemented.

    So, to get back to the original question: typically operators for builtin types are not implemented as functions in C or in C++, although it's legal to do it that way. But thinking of them as functions means you don't have to shift gears when you're looking at overloaded operators. So, the tutorial's assertion that "In C++, operators are implemented as functions" isn't actually correct. But it's a useful mental model for thinking about operators in C++.