这些类型的声明意味着什么

What do these type of declarations mean

提问人:mhsquare 提问时间:10/30/2023 最后编辑:chqrliemhsquare 更新时间:11/1/2023 访问量:132

问:

我在 C 中遇到了一些声明,无法理解它们的含义。

这里有什么意义和意思?这些用于函数。*const*restrictaio_suspend

const struct aiocb *const aiocb_list[]
const struct timespec *restrict timeout
C Linux UNIX

评论

2赞 UnholySheep 10/30/2023
你读过 en.cppreference.com/w/c/language/consten.cppreference.com/w/c/language/restrict
1赞 Some programmer dude 10/30/2023
该变量是一个数组(大小不明),由指向结构对象的常量指针组成,数组中的每个元素都是常量。了解顺时针/螺旋规则可能会有所帮助。aiocb_listaiocb
1赞 Some programmer dude 10/30/2023
该变量是指向常量结构的“受限”指针。timeouttimespec
2赞 Lundin 10/30/2023
restrict特别是,在没有任何上下文的情况下,意义不大 - 请发布完整的功能。由于是特定指针(通常是参数)与其他指针和/或文件范围变量之间的关系。restrict
0赞 Ben Voigt 10/31/2023
aiocb_list[]不是数组,而是指针,由于参数类型调整。

答:

3赞 Sanskar Omar 10/30/2023 #1

为了清楚起见,让我们分别看一下它们:

  1. const struct aiocb *const aiocb_list[]:

    • const应用于 :这表示中的指针指向常量结构对象,允许您使用这些指针以只读方式访问数据。struct aiocbaiocb_listaiocb
    • const应用于:数组本身是常量;存储在其中的指针无法更改。aiocb_list
  2. const struct timespec *restrict timeout:

    • const应用于:指向的数据是常量(只读)。struct timespectimeout
    • restrict应用于 :提示编译器没有别名(没有指向同一内存的其他指针),允许进行某些优化。timeout

: 对于 applied to ,这不会阻止相同对象的非常量视图存在于程序中的其他位置。对象本身本质上不是恒定的或只读的,而是通过这些指针强制执行只读视图。conststruct aiocbaiocb_list

评论

1赞 HolyBlackCat 10/30/2023
“其地址无法更改”->“存储在其中的指针无法更改”。无论 .const
1赞 Ben Voigt 10/31/2023
“这些指针指向的数据是常量(只读)”不正确。事实上,它提供了对象的只读视图,但没有什么能阻止同一对象的非常量视图存在于程序的其他地方。这些对象不是常量或只读的。aiocb_liststruct aiocb
1赞 arfneto 10/31/2023 #2

[1]const struct aiocb* const aiocb_list[];

这里

  • aiocb_list正在宣布。它是一个数组。
  • 它是一个常量数组
  • 常量是指针
  • 数组的每个元素都是指向 的指针,一个aiocbstruct
  • 数组本身也是常数,因为第一个const
  • 由于它没有被初始化,所以它必须是某些东西的一部分,比如参数列表,因为它是声明的const

因此,它是一个指向conststruct

这是一个使用这种结构的程序

输出

  function got 4 pointers
  Values are
  S
  O
  S
  O

法典

#include <stdio.h>

struct aiocb
{
    char what;
};

struct aiocb* action(
    size_t size, const struct aiocb* const aiocb_list[]);

int main(void)
{

    const struct aiocb data[4] = {
        [0] = {'a'},
        [1] = {'O'},
        [2] = {'S'},
        [3] = {'d'},
    };

    const struct aiocb* const list[] = {
        &data[2],
        &data[1],
        &data[2],
        &data[1],
        &data[0]
    };
    action(4, list);
    return 0;
}

struct aiocb* action(
    size_t size, const struct aiocb* const aiocb_list[])
{
    printf(
        "    function got %llu pointers\n    Values are\n",
        size);
    for (size_t i = 0; i < size; i += 1)
        printf("    %c\n", aiocb_list[i]->what);
    return NULL;
}

第二个例子:使用typedef

这是相同的代码,只是对 .一般来说,它更容易阅读并节省大量打字typedefstructstruct aiocb

#include <stdio.h>

typedef struct
{
    char what;
} Aiocb;

Aiocb* action(size_t, const Aiocb* const[]);

int main(void)
{
    const Aiocb data[4] = {
        [0] = {'a'},        [1] = {'O'},
        [2] = {'S'},        [3] = {'d'},
    };

    const Aiocb* const list[] = {
        &data[2], &data[1], &data[2], &data[1], &data[0]};
    action(4, list);
    return 0;
}

Aiocb* action(
    size_t size, const Aiocb* const aiocb_list[])
{
    printf(
        "    function got %llu pointers\n    Values are\n",
        size);
    for (size_t i = 0; i < size; i += 1)
        printf("    %c\n", aiocb_list[i]->what);
    return NULL;
}

请注意,这些赋值main

    list[0] = NULL; // error: array elements are const
    const Aiocb* other[5] = {0};
    // error: list can not point to other places
    list = other; 

不会编译,因为所有数组元素都是并且也是constlistconst

[2]const struct timespec *restrict timeout;

此处被声明为指向 .并且是恒定的。timeouttimespecstruct

restrict是程序员的承诺,即在其生命周期内,如此声明的指针将是唯一访问其目标的指针。对目标的访问仅限于此指针。

此保证为编译器提供了优化代码的机会。

一个很好的例子是 cppreference

int foo(int *a, int *b)
{
    *a = 5;
    *b = 6;
    return *a + *b;
}
 
int rfoo(int *restrict a, int *restrict b)
{
    *a = 5;
    *b = 6;
    return *a + *b;
}

以及可能生成的代码

; generated code on 64bit Intel platform:
foo:
    movl    $5, (%rdi)    ; store 5 in *a
    movl    $6, (%rsi)    ; store 6 in *b
    movl    (%rdi), %eax  ; read back from *a in case previous store modified it
    addl    $6, %eax      ; add 6 to the value read from *a
    ret
 
rfoo:
    movl      $11, %eax   ; the result is 11, a compile-time constant
    movl      $5, (%rdi)  ; store 5 in *a
    movl      $6, (%rsi)  ; store 6 in *b
    ret

我们看到,编译器知道除了 和 之外没有人指向函数内部的目标,可以返回并跳过之前的返回。ab11add

在某些情况下,可以大大节省执行时间和代码大小,因为编译器可以在大型循环中重新排序或跳过操作。restrict

评论

0赞 Ben Voigt 10/31/2023
“这是一个数组”不,不是。此处适用参数类型调整;它实际上是一个指针。
0赞 arfneto 10/31/2023
这是全部。最后的手段意味着什么。没有它们,编译器会说:它是一个指针。编译器说。无论如何,数组会衰减为指针。但它是一个数组,在示例中声明:C[](parameter) const Aiocb* const aiocb_list(parameter) const Aiocb* const aiocb_list[]mainconst Aiocb* const list[]
0赞 Ben Voigt 10/31/2023
谈论函数参数(问题中的函数,在你的答案中)。它是一个指针aio_suspendaction
0赞 arfneto 10/31/2023
@BenVoigt我不明白这一点。它是在 main 中声明的。它是一个数组。是的。它作为参数进入函数,在 .作为程序中的数组参数,你可以说它是一个指针。那又怎样?这是如何使用数组的示例,在 中声明,如问题中所示。它只是假的,甚至不是真的。请按原样查看。CCCmainstructaiocb
0赞 Fe2O3 11/1/2023
"当数组名称传递给函数时,传递的是初始元素的位置。在被调用的函数中,这个参数是一个局部变量,因此数组名称参数是一个指针,即一个包含地址的变量。谁错了?丹尼斯·里奇(Dennis Ritchie)还是阿夫内托(arfneto)?