在C中,运算符是否像C++中一样实现为函数?

huangapple go评论65阅读模式
英文:

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

问题

操作符在C中也是作为函数实现的吗?如果不是,那在C中是如何实现操作符的呢?

对于POD类型,操作符被实现为函数的方式可能是某些编译器独有的吗?

英文:

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?

答案1

得分: 2

这个陈述

> 在C++中,运算符被实现为函数

是错误的。

基本类型的运算符在C和C++中都是预定义的。

但在C++中,你可以将运算符重载为用户定义类型的函数。

在C中,没有这样的可能性。

英文:

This statement

> In C++, operators are implemented as functions

Is wrong.

Operators for fundamental types are predefined in C and C++.

But in C++ you may overload operators as functions for user-defined types.

In C there is absent such a possibility.

答案2

得分: 1

我一直觉得将运算符重载视为函数重载完全相同更容易理解:编译器使用参数的类型选择适当的重载。对于普通函数来说很简单:只需查看所有具有适当名称的函数,选择最佳匹配。

对于运算符重载来说,只要你愿意忘记编译器本身了解所有这些运算符的细节,它就同样容易。当我看到使用 + 运算符的代码时,我查看参数类型,并在头脑中应用选择最佳重载的规则。举一个非常简单的例子:

struct S {
};
int operator+(S s1, S s2) { return 42; }

S s;
int x1 = 1 + 1; // 使用“内置” operator+
int x2 = s + s; // 使用用户定义的 operator+

所以,这很容易;不管你如何思考这两个 + 运算符的基础是什么,都不重要。但让我们使它变得有点复杂:

struct T {
    operator S() const { return S(); }
};

S s;
T t;
int x3 = s + t;

现在怎么办?由于总和中涉及到了 S,编译器寻找接受 S+ 运算符,找到了我们之前定义的那个。并且因为 T 可以转换为 S,它可以将 t 转换为一个 S 对象,然后使用 operator+(S, S)。很简单,对吗?

现在,不再有一个到 S 的转换,让我们改为转换为 int

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

然后尝试类似的代码:

int i = 1;
U u;

int x4 = i + u;

刚刚做完前面的例子,很容易看出这里的分析类似:U 可以转换为 int,所以编译器可以将 u 转换为一个 int 对象,然后使用 operator+(int, int)

对我来说,这比拥有两个类别、内置类型和用户定义类型,以及两个不相关的运算符和如何分析它们的概念要简单得多。

因此,我将内置运算符视为如果它们是用户定义的运算符,以便弄清哪个重载应该被调用。

现在,这并不意味着编译器实际上使用函数调用来处理这些内置运算符。这可能会低效;实际上,现代编译器通常会直接生成代码以添加两个数字,通常作为一对机器指令。但这不是必需的;符合规范的实现实际上可以有一个函数来添加两个 int 值,并在看到类似 1 + 1 的情况下调用它。有时这是有意义的。考虑一个8位处理器和添加两个 long long 值的代码。是的,它可以内联执行。但在函数中实现8字节的加法并在需要时调用它可能会导致更小的代码;对于嵌入式系统来说,这可能很重要。

重点是,为了理解表达式的含义,不管 + 是否产生函数调用或一些内联代码都无关紧要。代码的含义不取决于它是如何实现的。

因此,回到最初的问题:通常情况下,内置类型的运算符在C或C++中并不是作为函数实现的,尽管可以这样做。但将它们视为函数意味着在查看重载运算符时不必切换思维方式。因此,教程中的说法“在C++中,运算符是作为函数实现的”实际上是不正确的。但它是一种有用的思维模型,用于思考C++中的运算符。

英文:

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++.

huangapple
  • 本文由 发表于 2023年3月15日 19:32:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/75744118.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定