阅读复杂的 const 声明的简单规则?

发布于 2024-12-05 20:34:16 字数 1517 浏览 1 评论 0原文

要读取复杂的指针声明,有

但这条规则没有提到如何读取const修饰符。

例如,在简单的指针声明中,const 可以通过多种方式应用:

char *buffer; // non-const pointer to non-const memory
const char *buffer; // non-const pointer to const memory
char const *buffer; // equivalent to previous declartion
char * const buffer = {0}; // const pointer to non-const memory
char * buffer const = {0}; // error
const char * const buffer = {0}; // const pointer to const memory

现在将 const 与指针声明的指针一起使用怎么样?

char **x; // no const;
const char **x;
char * const *x;
char * * const x;
const char * const * x;
const char * * const x;
const char * const * const x;

阅读这些声明的简单规则是什么? 哪些声明有意义?

顺时针/螺旋规则适用吗?

两个真实世界的示例

方法 ASTUnit::LoadFromCommandLine使用 const char ** 提供命令行参数(在 llvm clang 中 来源)。

getopt() 的自变量向量参数声明如下:

int getopt(int argc, char * const argv[], const char *optstring);

其中 char * const argv[] 相当于该上下文中的 char * const * argv

由于这两个函数使用相同的概念(指向字符串的指针向量来提供参数)并且声明不同 - 明显的问题是:为什么它们不同?其中一个比另一个更有意义吗?

意图应该是:const 修饰符应指定该函数不操作此向量的字符串,并且不更改向量的结构。

For reading complex pointer declarations there is the right-left rule.

But this rule does not mention how to read const modifiers.

For example in a simple pointer declaration, const can be applied in several ways:

char *buffer; // non-const pointer to non-const memory
const char *buffer; // non-const pointer to const memory
char const *buffer; // equivalent to previous declartion
char * const buffer = {0}; // const pointer to non-const memory
char * buffer const = {0}; // error
const char * const buffer = {0}; // const pointer to const memory

Now what about the use of const with a pointer of pointer declaration?

char **x; // no const;
const char **x;
char * const *x;
char * * const x;
const char * const * x;
const char * * const x;
const char * const * const x;

And what is an easy rule to read those declarations?
Which declarations make sense?

Is the Clockwise/Spiral Rule applicable?

Two real world examples

The method ASTUnit::LoadFromCommandLine uses const char ** to supply command line arguments (in the llvm clang source).

The argument vector parameter of getopt() is declared like this:

int getopt(int argc, char * const argv[], const char *optstring);

Where char * const argv[] is equivalent to char * const * argv in that context.

Since both functions use the same concept (a vector of pointers to strings to supply the arguments) and the declarations differ - the obvious questions are: Why do they differ? Makes one more sense than the other?

The intend should be: The const modifier should specify that the function does not manipulate strings of this vector and does not change the structure of the vector.

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

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

发布评论

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

评论(2

画离情绘悲伤 2024-12-12 20:34:17

(试图关注问题的其他方面)

const 的经验法则声明是从右到左读取它们,const修改下一个标记。例外:在声明的开头 const 修改前一个标记。

此异常背后有一个 基本原理 - 对于基本声明 const char c 对某些人来说比 char const c 更自然 - 据报道,const char c 的前体形式早于最终的 const 规则。

getopt

int getopt(int argc, char * const argv[], const char *optstring);

int getopt(int argc, char * const * argv, const char *optstring);

这意味着 argv 是一个指向 const 向量的指针,该向量由指向非常量字符串的指针组成。

但是人们会期望以下声明:(

int getopt(int argc, char const * const * argv, const char *optstring);

指向 const 向量的指针到 const 字符串)

因为 getopt() 不应该更改通过 argv 引用的字符串。

至少 char **(如 main() 中使用的)会自动转换为 char * const * argv

Clang

ASTUnit::LoadFromCommandLine(...,  const char **argv, ...);

这意味着 argv 是一个指向 const 字符串指针的非常量数组的指针。

同样,出于与上述相同的原因,人们会期望 const char * const *argv

但这更引人注目,因为 char ** 不转换const char **,例如

int main(int argc, char **argv) {
  const char **x = argv; // Compile error!
  return 0;
}

产生编译错误,而

int main(int argc, char **argv) {
  char * const *x = argv;
  return 0;
}

和 则

int main(int argc, char **argv) {
  const char * const *x = argv;
  return 0;
}

不会。

(Trying to focus on other aspects of the question)

The rule of thumb for const declarations is to read them from right to left and const modifies the next token. Exception: At the beginning of a declaration const modifies the previous token.

There is a rationale behind this exception - for elementary declarations const char c looks for some people more natural than char const c - and it is reported that a precursor form of const char c predates the final const rule.

getopt

int getopt(int argc, char * const argv[], const char *optstring);

or

int getopt(int argc, char * const * argv, const char *optstring);

Which means that argv is a pointer to const vector of pointers to non-const strings.

But one would expect following declaration:

int getopt(int argc, char const * const * argv, const char *optstring);

(pointer to const vector to const strings)

Because getopt() is not supposed to change the strings referenced via argv.

At least char ** (as used in main()) automatically converts to char * const * argv.

Clang

ASTUnit::LoadFromCommandLine(...,  const char **argv, ...);

Which means that argv is a pointer to a non-const array of pointers to const strings.

Again one would expect const char * const *argv for the same reason as above.

But this is more noticeable because char ** does not convert to const char **, e.g.

int main(int argc, char **argv) {
  const char **x = argv; // Compile error!
  return 0;
}

yields a compile error, where

int main(int argc, char **argv) {
  char * const *x = argv;
  return 0;
}

and

int main(int argc, char **argv) {
  const char * const *x = argv;
  return 0;
}

do not.

清风疏影 2024-12-12 20:34:16

const 修饰符很简单:它修改它前面的内容,除非
在它之前没有任何东西。所以:

char const* buffer;  // const modifies char
char* const buffer;  // const modifies *

等。一般来说,最好避免前面没有任何内容的形式
const,但在实践中,你会看到它们,所以你必须
请记住,当 const 之前没有类型时,您必须在逻辑上
将其移到第一种类型的后面。所以:

const char** buffer;

实际上是:

char const** buffer;

,即指向 const char 的指针。

最后,在函数声明中,后的 [] 读作前的 *
(再次强调,最好避免这种误导性的符号,但是
你将会看到它,所以你必须处理它。) 所以:

char * const argv[],  //  As function argument

是:

char *const * argv,

指向 char 的 const 指针的指针。

The const modifier is trivial: it modifies what precedes it, unless
nothing precedes it. So:

char const* buffer;  // const modifies char
char* const buffer;  // const modifies *

, etc. Generally, It's best to avoid the forms where nothing precedes
the const, but in practice, you're going to see them, so you have to
remember that when no type precedes the const, you have to logically
move it behind the first type. So:

const char** buffer;

is in fact:

char const** buffer;

, i.e. pointer to pointer to const char.

Finally, in a function declaration, a [] after reads as a * before.
(Again, it's probably better to avoid this misleading notation, but
you're going to see it, so you have to deal with it.) So:

char * const argv[],  //  As function argument

is:

char *const * argv,

a pointer to a const pointer to a char.

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