Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/flutter/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
列表、指针的命名别名和C语言中的语义_C_Semantics - Fatal编程技术网

列表、指针的命名别名和C语言中的语义

列表、指针的命名别名和C语言中的语义,c,semantics,C,Semantics,我一直在研究列表,这是我在C编程语言项目中的一部分。仅供参考,条目结构和列表结构是非常基本的数据结构,定义如下 typedef struct entry entry_t; typedef struct list list_t; struct entry { void * data; entry_t * next; }; struct list { size_t size; entry_t * head; entry_t * tail; }; head

我一直在研究列表,这是我在C编程语言项目中的一部分。仅供参考,条目结构和列表结构是非常基本的数据结构,定义如下

typedef struct entry entry_t;
typedef struct list list_t;

struct entry
{
    void * data;
    entry_t * next;
};

struct list
{
    size_t size;
    entry_t * head;
    entry_t * tail;
};
head
tail
分别指向第一个和最后一个条目。列表中只有一个条目,
head
tail
应该指向同一个条目。此外,还有这样一个片段可以删除列表中的所有条目

list_t list;
entry_t * current, * next;
for(
    current=list->head,
    next=current->next,
    free(current);
    current!=list->tail;
    current=next,
    next=current->next,
    free(current)
);

问题是,在释放
current
指针后,将对指向的内存地址
current
list->tail
的值进行比较。假设
current
list->tail
现在指向同一内存块,然后
current
被释放,那么计算的结果是什么?更重要的是,在您的经验中,结果(无论是什么)在所有不同的编译器中都是确定的吗?在我的例子中,程序是在MSVC中编译并正确运行的,这表示在释放
current
后,内存地址
current
list->tail
的值是相等的。

这一点并不重要,但如果您正在清除列表,请原谅显而易见的问题,但谁在乎tail(或大小)是什么呢。不管怎样,它们都将是无效的。为什么不简单地:

// assuming list is a valid
list_t* list;

while (list->head)
{
    entry_t *tmp = list->head;
    list->head = list->head->next;
    free(tmp);
}
list->head = list->tail = NULL;
list->size = 0;
评估的结果是什么

C标准表示结果未定义

更重要的是,结果(无论是什么)是确定的吗 根据您的经验,在所有不同的编译器中

内存一旦被进程分配,通常在进程终止之前不会返回操作系统。
我所知道的所有编译器都将计算
current=list->tail
为false,不引发异常

从技术上讲,你是在违反规则。第6.2.4(2)条

对象的生存期是程序执行期间保证为其保留存储的部分。对象存在,具有恒定地址,并在其整个生命周期中保留其最后存储的值。如果对象在其生存期之外被引用,则该行为未定义。当指针指向(或刚刚经过)的对象到达其生命周期结束时,指针的值将变得不确定

在C2011标准的n1570草案中(在C99标准的相同位置几乎相同),在
free
ing
current
之后,其值变得不确定(如果
current
list->tail
free
调用它之前恰好指向同一个对象,那么
list->tail
的值也变得不确定。)因此在比较中使用它会调用未定义的行为

在一个假设的实现中,跟踪指针的有效性并检查它的每次比较等,它可能崩溃或做其他有趣的事情

然而,在实践中,我并不期望任何实现能够做到这一点,因此它几乎肯定会产生预期的结果


实际上,有一个平台在进行跟踪。但是,这会将所有无效指针视为
NULL
,因此,如果我理解正确,即使在那里,所讨论的代码也会产生预期的结果。

下面是
for loop
的实现

entry_t *current,*prev,*next;  

  for(
        current = list->head;

        current != NULL;

        prev=current,
        current = current->next,
        free(prev),
        prev=NULL
    );

空闲(当前)
使用
current!=list->tail
是未定义的行为,因此它依赖于编译器,不是吗?@hmjd:在这里使用指针而不是结构的成员,所以,你说它很好。@hmjd:是的,但是OP以我感到困惑的方式表述了问题。。看到他的问题的最后一行了吗?很好……我也在考虑这样做 .+1@Deniel:这就是为什么在释放指针后使其为空是最佳做法,对吗?最佳做法是使其(以及指向同一对象的所有其他指针)为空在
free
之后立即退出范围。将其设置为
NULL
是第二好的选择。顺便说一句,Daniel.AS/400有一个执行此操作的平台。所有指针都是128位线性地址,并且在主地址页中存在一个计算位集,其中每个位表示进程地址空间的16字节偏移量。O只有当指针(必须是16字节对齐的)持有有效的(意味着可取消引用的)地址时,该位才被点亮。任何没有点亮位的指针值都被视为NULL。令人惊讶的是,这意味着
int*p=(int*)1;if(p)printf(“foo”);
不打印任何内容。同样的设置,它意味着
if(p==NULL)
evals to true。这是一个令人惊奇的系统。哦,这是邪恶的,@WhozCraig。绝对邪恶。令人惊奇。这是一个伟大的问题。我从未研究过omfg之外的问题。他们真的这样做了???阶段。我猜一个单独的堆映射,可以追溯到他们相关的指针位偏移量。很难说。