简体   繁体   English

C中数组的const和typedef

[英]const and typedef of arrays in C

In C, it's possible to typedef an array, using this construction : 在C中,可以使用以下结构来typedef一个数组:

typedef int table_t[N];

Here, table_t is now defined as an array of N int . 这里, table_t现在被定义为N int的数组。 Any variable declared such as table_t t; 声明的任何变量,如table_t t; will now behave as a normal array of int . 现在将表现为int的正常数组。

The point of such construction is to be used as an argument type in a function, such as : 这种构造的要点是在函数中用作参数类型,例如:

int doSomething(table_t t);

A relatively equivalent function prototype could have been : 一个相对等效的函数原型可能是:

int doSomething(int* t);

The merit of the first construction is that it enforces N as the size of the table. 第一种结构的优点是它强制N作为表的大小。 In many circumstances, it's safer to enforce this property, rather than relying on the programmer to properly figure out this condition. 在许多情况下,强制执行此属性更安全,而不是依赖程序员来正确地找出这种情况。

Now it's all good, except that, in order to guarantee that the content of table will not be modified, it's necessary to use the const qualifier. 现在一切都很好,除了为了保证表的内容不会被修改,有必要使用const限定符。

The following statement is relatively simple to understand : 以下陈述相对简单易懂:

int doSomething(const int* t);

Now, doSomething guarantee that it will not modify the content of the table passed as a pointer. 现在, doSomething保证它不会修改作为指针传递的表的内容。 Now, what about this almost equivalent construction ? 现在,这几乎相同的建筑怎么样? :

int doSomething(const table_t t);

What is const here ? const在这里是什么? the content of the table, or the pointer to the table ? 表的内容,或指向表的指针? If it's the pointer which is const , is there another way (C90 compatible) to retain the ability to define the size of the table and to tell that its content will be const ? 如果它是const的指针,是否有另一种方式(C90兼容)保留定义表大小的能力并告诉它的内容将是const?

Note that it's also necessary sometimes to modify the content of the table, so the const property cannot be embedded into the typedef definition. 请注意,有时还需要修改表的内容,因此const属性不能嵌入到typedef定义中。

[ Edit ] Thanks for the excellent answers received so far. [ 编辑 ]感谢到目前为止收到的优秀答案。 To summarize : 总结一下:

  • The initial assumption of typedef enforcing size N was completely wrong. typedef强制执行大小N的初始假设是完全错误的。 It basically behaves the same as a normal pointer. 它基本上与普通指针的行为相同。
  • The const property will also behave the same as if it was a pointer (in stark contrast with a typedef to a pointer type, as underlined by @random below) const属性的行为也与指针一样(与指针类型的typedef形成鲜明对比,如下面的@random所示)
  • To enforce a size (which was not the initial question, but end up being quite important now...), see Jonathan's answer 要强制执行一个大小(这不是最初的问题,但最终现在非常重要......),请参阅Jonathan的回答

First, you are mistaken, the function prototypes 首先,你错了,函数原型

int doSomething(table_t t);
int doSomething(int* t);

are exactly equivalent. 完全相同。 For function parameters, the first array dimension is always rewritten as a pointer. 对于函数参数,始终将第一个数组维重写为指针。 So there is no guarantee for the size of the array that is received. 因此无法保证接收到的阵列大小。

const -qualification on arrays always applies to the base type of the array, so the two declarations 数组的const -qualification总是适用于数组的基类型,所以这两个声明

const table_t a;
int const a[N];

are equivalent, and for functions parameters we have 是等价的,我们有函数参数

int doSomething(const table_t t);
int doSomething(int const* t);

The content of the table will be constant. 表的内容将是不变的。 Easily checked with this code. 使用此代码轻松检查。

#include<stdio.h>

typedef int table_t[3];
void doSomething(const table_t t)
{
    t++;    //No error, it's a non-const pointer.
    t[1]=3; //Error, it's a pointer to const.

}

int main()
{
    table_t t={1,2,3};
    printf("%d %d %d %ld",t[0],t[1],t[2],sizeof(t));
    t[1]=5;
    doSomething(t);
    return 0;
}

The merit of the first construction is that it enforces N as the size of the table. 第一种结构的优点是它强制N作为表的大小。

I'm not sure what you mean here. 我不确定你的意思。 In what contexts would it "enforce" it? 在什么情况下它会“强制执行”它? If you declare a function as 如果将函数声明为

int doSomething(table_t t);

array size will not be enforced. 数组大小将不会被强制执行。 I order to enforce the size, you'd have to go a different route 我要强制执行大小,你必须走另一条路

int doSomething(table_t *t); // equivalent to 'int (*t)[N]'

What is const here ? const在这里是什么?

As for const ... When const is applied to array type it "drops down" all the way to array elements. 至于const ...当const应用于数组类型时,它“一直”下降到数组元素。 This means that const table_t is an array of constant int s, ie it is equivalent to const int [N] type. 这意味着const table_t是一个常量int的数组,即它等效于const int [N]类型。 The end result of this is that the array becomes non-modifiable. 最终结果是数组变得不可修改。 In function parameter declaration context const table_t will be converted into const int * . 在函数参数声明上下文中, const table_t将被转换为const int *

However, note one peculiar detail that is not immediately obvious in this case: the array type itself remains non-const-qualified. 但是,请注意在这种情况下并不是很明显的一个特殊细节:数组类型本身仍然是非const限定的。 It is the individual elements that become const . 成为const个别元素 In fact, it is impossible to const-qualify the array type itself in C. Any attempts to do so will make const-qualification to "sift down" to individual elements. 实际上,不可能在C中对数组类型本身进行const限定。任何尝试这样做都会使const限定为“筛选”到单个元素。

This peculiarity leads to rather unpleasant consequences in array const-correctness. 这种特性导致阵列常量正确性产生相当不愉快的后果。 For example, this code will not compile in C 例如,此代码不会在C中编译

table_t t;
const table_t *pt = &t;

even though it looks quite innocently from the const-correctness point of view and will compile for any non-array object type. 即使它从const-correctness的角度看起来非常无辜,并且将为任何非数组对象类型进行编译。 C++ language updated its const-correctness rules to resolve this issue, while C continues to stick to its old ways. C ++语言更新了它的const-correctness规则来解决这个问题,而C继续坚持它的旧方法。

Array types and pointer types are not 100% equivalent, even in this context where you do ultimately get a pointer type for the function parameter. 数组类型和指针类型不是100%等效的,即使在最终获得函数参数指针类型的上下文中也是如此。 Your mistake is in assuming that const would have acted the same way if it were a pointer type. 你的错误在于假设如果它一个指针类型, const会以相同的方式行事。

To expand on ARBY's example: 要扩展ARBY的例子:

typedef int table_t[3];
typedef int *pointer_t;

void doSomething(const table_t t)
{
    t++;    //No error, it's a non-const pointer.
    t[1]=3; //Error, it's a pointer to const.
}

void doSomethingElse(const pointer_t t)
{
    t++;    //Error, it's a const pointer.
    t[1]=3; //No error, it's pointer to plain int
}

It does act similarly to const int * , but const pointer_t is instead equivalent to int * const . 它的作用与const int *相似,但const pointer_t相当于int * const

(Also, disclaimer, user-defined names ending with _t are not allowed by POSIX, they're reserved for future expansion) (另外,免责声明,POSIX不允许以_t结尾的用户定义名称,它们保留用于将来的扩展)

The standard 6.7.6.3 says: 标准6.7.6.3说:

A declaration of a parameter as ''array of type'' shall be adjusted to ''qualified pointer to type'' 参数声明为''类型数组''应调整为''限定指向类型''

Meaning that when you declare a function parameter as a const int array type, it decays into a pointer to const int (first element in array). 这意味着当您将函数参数声明为const int数组类型时,它会衰减为指向const int (数组中的第一个元素)的指针。 Equivalent to const int* in this case. 在这种情况下等效于const int*

Also note that because of the above mentioned rule, the array size specified adds no additional type safety! 另请注意,由于上述规则,指定的数组大小不会增加其他类型的安全性! This is one big flaw in the C language, but that's how it is. 这是C语言中的一个重大缺陷,但就是这样。

Still, it is good practice to declare the array with fixed width like you have, because static analysers or clever compilers may produce a diagnostic about different types. 尽管如此,最好使用固定宽度声明数组,因为静态分析器或聪明的编译器可能会生成不同类型的诊断。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM