为什么解引用运算符(*)也用于声明指针?

发布于 2024-12-23 20:55:48 字数 641 浏览 6 评论 0原文

我不确定这是否是一个适当的编程问题,但它一直困扰着我,我想知道我是否是唯一的一个。

最初学习 C++ 时,我了解引用的概念,但指针让我感到困惑。你问为什么?因为你声明指针的方式。

请考虑以下情况:

void foo(int* bar)
{
}


int main()
{
    int x = 5;
    int* y = NULL;

    y = &x;
    *y = 15;     
    foo(y);

}

函数 foo(int*) 采用 int 指针作为参数。由于我已将 y 声明为 int 指针,因此我可以将 y 传递给 foo,但是当第一次学习 C++ 时我将 * 符号与取消引用相关联,因此我认为需要传递一个取消引用的 int 。我会尝试将 *y 传递到 foo 中,这显然不起作用。

使用单独的运算符来声明指针不是更容易吗? (或用于取消引用)。例如:

void test(int@ x)
{
}

I'm not sure if this is a proper programming question, but it's something that has always bothered me, and I wonder if I'm the only one.

When initially learning C++, I understood the concept of references, but pointers had me confused. Why, you ask? Because of how you declare a pointer.

Consider the following:

void foo(int* bar)
{
}


int main()
{
    int x = 5;
    int* y = NULL;

    y = &x;
    *y = 15;     
    foo(y);

}

The function foo(int*) takes an int pointer as parameter. Since I've declared y as int pointer, I can pass y to foo, but when first learning C++ I associated the * symbol with dereferencing, as such I figured a dereferenced int needed to be passed. I would try to pass *y into foo, which obviously doesn't work.

Wouldn't it have been easier to have a separate operator for declaring a pointer? (or for dereferencing). For example:

void test(int@ x)
{
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

橪书 2024-12-30 20:55:48

C 语言的发展中,Dennis Ritchie 解释了他的推理因此:

第二个最明显区分 C 与其语言的创新
前身是这种更完整的类型结构,尤其是它的
声明语法中的表达式...给定任何对象
类型,应该可以描述一个收集的新对象
几个到一个数组中,从一个函数中产生它,或者是一个指向
它......[这]导致了
名称的声明语法与表达式语法的镜像相同
其中名称通常出现。
因此,

int i, *pi, **ppi; 声明一个整数、一个指向整数的指针、一个
指向整数的指针。这些声明的语法
反映了 i、*pi 和 **ppi 都产生 int 类型的观察结果
当用在表达式中时。

类似地,int f(), *f(), (*f)(); 声明
返回整数的函数,返回指向指针的函数
整数,指向返回整数的函数的指针。 int *api[10],
(*pai)[10];
声明一个指向整数的指针数组,以及一个指向
整数数组。

在所有这些情况下,声明
变量类似于其在类型为 one 的表达式中的用法
在声明的开头命名

语法上的意外导致了人们对理解的复杂性的认识
语言。间接运算符,在 C 中拼写为 *,在语法上是
一元前缀运算符,就像 BCPL 和 B 中一样。这在
简单的表达式,但在更复杂的情况下,括号是
需要直接解析。例如,要区分
间接通过函数调用返回的值
由指针指定的函数,可以写成*fp()和(*pf)()
分别。表达式中使用的风格贯穿于
声明,因此可以声明名称

int *fp(); int (*pf)();

在更华丽但仍然现实的情况下,
事情变得更糟:int *(*pfp)(); 是一个指向函数的指针
返回一个指向整数的指针。

有两种效果发生。
最重要的是,C有一套相对丰富的描述方式
类型(例如,与 Pascal 相比)。语言声明为
表达为 C——例如 Algol 68——描述同样难以描述的物体
理解,只是因为对象本身很复杂。一个
第二个效果归因于语法的细节。 C 中的声明必须是
以“由内而外”的方式阅读,许多人觉得难以掌握。
Sethi [Sethi 81] 观察到许多嵌套
如果间接的话,声明和表达式会变得更简单
运算符已被视为后缀运算符而不是前缀,但是
到那时改变已经太晚了。

In The Development of the C Language, Dennis Ritchie explains his reasoning thusly:

The second innovation that most clearly distinguishes C from its
predecessors is this fuller type structure and especially its
expression in the syntax of declarations... given an object of any
type, it should be possible to describe a new object that gathers
several into an array, yields it from a function, or is a pointer to
it.... [This] led to a
declaration syntax for names mirroring that of the expression syntax
in which the names typically appear.
Thus,

int i, *pi, **ppi; declare an integer, a pointer to an integer, a
pointer to a pointer to an integer. The syntax of these declarations
reflects the observation that i, *pi, and **ppi all yield an int type
when used in an expression.

Similarly, int f(), *f(), (*f)(); declare
a function returning an integer, a function returning a pointer to an
integer, a pointer to a function returning an integer. int *api[10],
(*pai)[10];
declare an array of pointers to integers, and a pointer to
an array of integers.

In all these cases the declaration of a
variable resembles its usage in an expression whose type is the one
named at the head of the declaration
.

An accident of syntax contributed to the perceived complexity of the
language. The indirection operator, spelled * in C, is syntactically a
unary prefix operator, just as in BCPL and B. This works well in
simple expressions, but in more complex cases, parentheses are
required to direct the parsing. For example, to distinguish
indirection through the value returned by a function from calling a
function designated by a pointer, one writes *fp() and (*pf)()
respectively. The style used in expressions carries through to
declarations, so the names might be declared

int *fp(); int (*pf)();

In more ornate but still realistic cases,
things become worse: int *(*pfp)(); is a pointer to a function
returning a pointer to an integer.

There are two effects occurring.
Most important, C has a relatively rich set of ways of describing
types (compared, say, with Pascal). Declarations in languages as
expressive as C—Algol 68, for example—describe objects equally hard to
understand, simply because the objects themselves are complex. A
second effect owes to details of the syntax. Declarations in C must be
read in an `inside-out' style that many find difficult to grasp.
Sethi [Sethi 81] observed that many of the nested
declarations and expressions would become simpler if the indirection
operator had been taken as a postfix operator instead of prefix, but
by then it was too late to change.

可是我不能没有你 2024-12-30 20:55:48

如果这样写的话,原因就更清楚了:

int x, *y;

也就是说,x和*y都是整数。因此 y 是一个 int *。

The reason is clearer if you write it like this:

int x, *y;

That is, both x and *y are ints. Thus y is an int *.

沙与沫 2024-12-30 20:55:48

这是早于 C++ 的语言决定,因为 C++ 从 C 继承了它。我曾经听说其动机是声明和使用是等效的,即给定声明 int *p;表达式 *p 的类型为 int,与 int i; 的表达式 i 的类型相同类型int

That is a language decision that predates C++, as C++ inherited it from C. I once heard that the motivation was that the declaration and the use would be equivalent, that is, given a declaration int *p; the expression *p is of type int in the same way that with int i; the expression i is of type int.

尴尬癌患者 2024-12-30 20:55:48

因为委员会以及在 C++ 标准化之前的几十年里开发 C++ 的人决定 * 应保留其原始的三个含义

  • 指针类型
  • 解引用运算
  • 乘法

符 正确地表明 * (以及类似的 &)的多重含义令人困惑。多年来我一直认为它们是语言新手理解的重大障碍。


为什么不为 C++ 选择另一个符号?

向后兼容性是根本原因...最好在新的上下文中重用现有符号,而不是通过将以前非运算符转换为新含义来破坏 C 程序。


为什么不为 C 选择另一个符号呢?

虽然不可能确切知道,但可以并且已经提出了一些论据。最重要的是这样的想法:

当标识符出现在与声明符形式相同的表达式中时,它会生成指定类型的对象。 {K&R,p216}

这也是为什么 C 程序员倾向于[需要引用]更喜欢将星号向右而不是向左对齐,即:

int *ptr1; // roughly C-style
int* ptr2; // roughly C++-style

尽管这两种变体都在两种语言的程序中都存在语言,各不相同。

Because the committee, and those that developed C++ in the decades before its standardisation, decided that * should retain its original three meanings:

  • A pointer type
  • The dereference operator
  • Multiplication

You're right to suggest that the multiple meanings of * (and, similarly, &) are confusing. I've been of the opinion for some years that it they are a significant barrier to understanding for language newcomers.


Why not choose another symbol for C++?

Backwards-compatibility is the root cause... best to re-use existing symbols in a new context than to break C programs by translating previously-not-operators into new meanings.


Why not choose another symbol for C?

It's impossible to know for sure, but there are several arguments that can be — and have been — made. Foremost is the idea that:

when [an] identifier appears in an expression of the same form as the declarator, it yields an object of the specified type. {K&R, p216}

This is also why C programmers tend to[citation needed] prefer aligning their asterisks to the right rather than to the left, i.e.:

int *ptr1; // roughly C-style
int* ptr2; // roughly C++-style

though both varieties are found in programs of both languages, varyingly.

缺⑴份安定 2024-12-30 20:55:48

专家 C 编程:深度 C 秘密的第 65 页包括以下内容:然后,还有 C 哲学,即对象的声明应该看起来像它的使用。

C 编程语言,第二版(又名 K&R) 包括:声明符读作一个断言,当它的标识符出现在与声明符相同形式的表达式中时,它会生成指定类型的对象。

我更喜欢 van der Linden 的说法。

Page 65 of Expert C Programming: Deep C Secrets includes the following: And then, there is the C philosophy that the declaration of an object should look like its use.

Page 216 of The C Programming Language, 2nd edition (aka K&R) includes: A declarator is read as an assertion that when its identifier appears in an expression of the same form as the declarator, it yields an object of the specified type.

I prefer the way van der Linden puts it.

傲鸠 2024-12-30 20:55:48

哈哈,我感受到你的痛苦,我也遇到了同样的问题。

我认为指针应该声明为 &int 因为指针是某物的地址是有意义的。

后来我自己想了一下,C中的每个类型都可以向后读取,比如

int * const x

可以读取为

x const * int

常量x,当取消引用时(用* 表示),其类型为int
因此,必须取消引用的东西必须是指针。

Haha, I feel your pain, I had the exact same problem.

I thought a pointer should be declared as &int because it makes sense that a pointer is an address of something.

After a while I thought for myself, every type in C can be read backwards, like

int * const x

can be read as

x const * int

A constant x, when dereferenced (signaled with *) is of type int.
So something that has to be dereferenced, has to be a pointer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文