受限指针问题

发布于 2024-09-25 08:23:55 字数 529 浏览 6 评论 0原文

我对有关受限指针的规则有点困惑。也许有人可以帮助我。

  1. 如下定义嵌套受限指针是否合法:

    int* 限制 a;
    int* 限制 b;
    
    
    a = malloc(sizeof(int));
    
    
    // b = a; <-- 这里的赋值是非法的,需要在子块中进行
    // *b = 兰特();
    
    
    同时(1)
    {
        b = a; // 这合法吗?假设 'b' 在 while() 块之外没有被修改
        *b = 兰特();
    }
    
  2. 按如下方式派生受限指针值是否合法:

    int* 限制 c;
    int* 限制 d;
    
    
    c = malloc(sizeof(int*)*101);
    d = c;
    
    
    for(int i = 0; i < 100; i++)
    {
        *d = 我;
        d++;
    }
    
    
    c = d; // c 现在设置为 101 元素,假设 d 未被访问,这是否合法?
    *c = 兰特();
    

谢谢! 安德鲁

I'm a little confused about the rules regarding restricted pointers. Maybe someone out there can help me out.

  1. Is it legal to define nested restricted pointers as follows:

    int* restrict a;
    int* restrict b;
    
    
    a = malloc(sizeof(int));
    
    
    // b = a; <-- assignment here is illegal, needs to happen in child block
    // *b = rand();
    
    
    while(1)
    {
        b = a;  // Is this legal?  Assuming 'b' is not modified outside the while() block
        *b = rand();
    }
    
  2. Is it legal to derive a restricted pointer value as follows:

    int* restrict c;
    int* restrict d;
    
    
    c = malloc(sizeof(int*)*101);
    d = c;
    
    
    for(int i = 0; i < 100; i++)
    {
        *d = i;
        d++;
    }
    
    
    c = d; // c is now set to the 101 element, is this legal assuming d isn't accessed?
    *c = rand();
    

Thanks!
Andrew

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

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

发布评论

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

评论(2

鸠书 2024-10-02 08:23:55

作为参考,这里是 restrict 限定符的相当复杂的定义(来自 C99 6.7.3.1“Restrict 的正式定义”):

令 D 为普通的声明
标识符提供了一种手段
将对象 P 指定为
指向类型 T 的限制限定指针。

如果 D 出现在块内并且
没有存储类别
extern,令 B 表示该块。如果D
出现在参数列表中
函数的声明
定义,令 B 表示
关联块。否则,让B
表示 main 块(或块
无论调用什么函数
独立程序启动
环境)。

接下来,一个指针
据说表达式 E 是基于
对象 P if (在某个序列点
在执行B之前
E) 的评估将 P 修改为点
到数组对象的副本到
它以前指出的将会改变
E 的值。请注意,“基于”是
仅为表达式定义
指针类型。

在 B 的每次执行期间,令 L 为
任何具有基于 P 的 &L 的左值。如果
L 用于访问值
它指定的对象 X,并且 X 是
也修改了(以任何方式),那么
以下要求适用:T 应
不是 const 限定的。每隔一个
左值用于访问 X 的值
还应有其地址基于
P. 每次修改 X 的访问都应
也可以考虑修改 P,因为
本款的目的。如果P
被分配了一个指针的值
表达式 E 基于另一个
受限指针对象P2,
与块 B2 关联,则
B2的执行应在
B 的执行,或
B2的执行应在以下时间之前结束
作业。如果这些
不满足要求,则
行为未定义。

这里 B 的执行意味着
执行的一部分
程序将对应于
标量类型对象的生命周期
和自动存储时间
与 B 相关。

我对上述内容的阅读意味着,在你的第一个问题中,即使在“子”块内,a 也不能分配给 b - 结果是未定义的。如果 b 在该“子块”中声明,则可以进行此类分配,但由于 b 是在与 a 相同的范围内声明的,无法进行分配。

对于问题 2,cd 之间的赋值也会导致未定义的行为(在这两种情况下)。

标准中的相关部分(对于两个问题)是:

如果P被赋予a的值
指针表达式 E 基于
另一个受限指针对象P2,
与块 B2 关联,则
B2的执行应在
B 的执行,或
B2的执行应在以下时间之前结束
作业。

由于受限指针与同一块关联,因此块 B2 不可能在 B 执行之前开始,也不可能在赋值之前结束 B2(因为 B 和 B2 是同一块)。

该标准给出了一个例子,使这一点非常清楚(我认为 - restrict 定义的 4 个短段落的清晰度与 C++ 的名称解析规则相当):

示例 4:

限制分配的规则
受限指针不
区分函数调用
和一个等效的嵌套块。
除了一处例外,只有
之间的“从外到内”分配
嵌套中声明的受限指针
块具有定义的行为。

<前><代码>{
int * 限制 p1;
int * 限制 q1;

p1 = q1; // 未定义的行为

{
int * 限制 p2 = p1; // 有效的
int * 限制 q2 = q1; // 有效的
p1 = q2; // 未定义的行为
p2 = q2; // 未定义的行为
}
}

For reference, here's the restrict qualifier's rather convoluted definition (from C99 6.7.3.1 "Formal definition of restrict"):

Let D be a declaration of an ordinary
identifier that provides a means of
designating an object P as a
restrict-qualified pointer to type T.

If D appears inside a block and
does not have storage class
extern, let B denote the block. If D
appears in the list of parameter
declarations of a function
definition, let B denote the
associated block. Otherwise, let B
denote the block of main (or the block
of whatever function is called at
program startup in a freestanding
environment).

In what follows, a pointer
expression E is said to be based on
object P if (at some sequence point
in the execution of B prior to the
evaluation of E) modifying P to point
to a copy of the array object into
which it formerly pointed would change
the value of E. Note that "based" is
defined only for expressions with
pointer types.

During each execution of B, let L be
any lvalue that has &L based on P. If
L is used to access the value of the
object X that it designates, and X is
also modified (by any means), then the
following requirements apply: T shall
not be const-qualified. Every other
lvalue used to access the value of X
shall also have its address based on
P. Every access that modifies X shall
be considered also to modify P, for
the purposes of this subclause. If P
is assigned the value of a pointer
expression E that is based on another
restricted pointer object P2,
associated with block B2, then either
the execution of B2 shall begin before
the execution of B, or the
execution of B2 shall end prior to
the assignment. If these
requirements are not met, then the
behavior is undefined.

Here an execution of B means that
portion of the execution of the
program that would correspond to the
lifetime of an object with scalar type
and automatic storage duration
associated with B.

My reading of the above means that in your first question, a cannot be assigned to b, even inside a "child" block - the result is undefined. Such an assignment could be made if b were declared in that 'sub-block', but since b is declared at the same scope as a, the assignment cannot be made.

For question 2, the assignments between c and d also result in undefined behavior (in both cases).

The relevant bit from the standard (for both questions) is:

If P is assigned the value of a
pointer expression E that is based on
another restricted pointer object P2,
associated with block B2, then either
the execution of B2 shall begin before
the execution of B, or the
execution of B2 shall end prior to
the assignment.

Since the restricted pointers are associated with the same block, it's not possible for block B2 to begin before the execution of B, or for B2 to end prior to the assignment (since B and B2 are the same block).

The standard gives an example that makes this pretty clear (I think - the clarity of the restrict definition's 4 short paragraphs is on par with C++'s name resolution rules):

EXAMPLE 4:

The rule limiting assignments between
restricted pointers does not
distinguish between a function call
and an equivalent nested block.
With one exception, only
"outer-to-inner" assignments between
restricted pointers declared in nested
blocks have defined behavior.

{
    int * restrict p1;
    int * restrict q1;

    p1 = q1; //  undefined behavior

    {
        int * restrict p2 = p1; //  valid
        int * restrict q2 = q1; //  valid
        p1 = q2; //  undefined behavior
        p2 = q2; //  undefined behavior
    }
}
云雾 2024-10-02 08:23:55

restrict 类型限定符向编译器发出指示,如果 restrict 限定指针所寻址的内存被修改,则其他指针将不会被修改。访问相同的内存。编译器可能会选择优化涉及 restrict 限定指针的代码,否则可能会导致不正确的行为。 程序员有责任确保限制限定指针按其预期用途使用。否则,可能会导致未定义的行为。 (link)

正如您从上面的描述中看到的,您的两个赋值都是非法的,这可能在某些编译器生成的可执行文件中有效,但在其他编译器中会中断。不要指望编译器本身会发出错误或警告,因为 restrict 只是提供了执行某些优化的机会,它可以选择不执行,就像 volatile 的情况一样>。

The restrict type qualifier is an indication to the compiler that, if the memory addressed by the restrict-qualified pointer is modified, no other pointer will access that same memory. The compiler may choose to optimize code involving restrict-qualified pointers in a way that might otherwise result in incorrect behavior. It is the responsibility of the programmer to ensure that restrict-qualified pointers are used as they were intended to be used. Otherwise, undefined behavior may result. (link)

As you can see from the above description, both your assignments are illegal, that may work in executables produced by some compilers but break in others. Don't expect the compiler itself to emit errors or warnings as restrict just gives an opportunity to perform certain optimization, which it can choose not to perform, like in the case of volatile.

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