【问题标题】:Null pointer detection in tcctcc 中的空指针检测
【发布时间】:2017-07-07 17:41:57
【问题描述】:

我创建了一个非常简单的链表,并注意到我的代码的 tcc filename.ctcc filename.c -run 的输出有所不同:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct llist {
    struct llist *next;
    struct llist *last;
    struct llist *first;
    int value;
    int item;
    int *length;
};

struct llist *newList(int v){

    struct llist *l1 = malloc(sizeof(struct llist)); 
    l1 -> length = malloc(sizeof(int));
    *l1 -> length = 1;

    l1 -> value = v;    
    l1 -> item = 0;    
    l1 -> first = l1;

    return l1;
}

struct llist *appendList(struct llist *l1, int v){

    struct llist *l2 = malloc(sizeof(struct llist));

    l2 -> value = v;
    l2 -> last = l1;
    l2 -> first = l1 -> first;
    l2 -> length = l1 -> length; 
    *l2 -> length += 1; 
    l2 -> item = l1 -> item + 1;

    l1 -> next = l2;

    return l2;    
};

int main(){
    struct llist *list = newList(4);
    list = appendList(list, 6);
    list = appendList(list, 8);
    list = appendList(list, 10);

    list = list -> first;

    int end = 0;
    while(end==0){

        printf("VAL: %d\n", list -> value);

        if(list -> next == NULL){
            printf("END\n");
            end = 1;
        }else{

            list = list -> next;
        }
    }


    return 0;
}

使用tcc filename.c 编译然后运行它会产生我预期的输出:

VAL: 4
VAL: 6
VAL: 8
VAL: 10
END

这也是我在 GCC 和 clang 中得到的输出。

当我使用tcc filename.c -run 时,我得到:

VAL: 4
VAL: 6
VAL: 8
VAL: 10
VAL: 27092544
VAL: 1489483720
VAL: 0
END

最后一个数字总是为零,而其他两个额外的值每次运行时都不同。

我想出了在newList 函数中添加l1 -&gt; next = NULL; 并在appendList 函数中添加l2 -&gt; next = NULL; 的解决方案。

但我想知道为什么输出会有所不同。编译器中是否存在错误,或者我没有初始化指向 NULL 的指针是错误的,即使它在大多数编译器中都有效?

【问题讨论】:

  • 因为没有分配NULL,您正在调用未定义的行为
  • 使用未初始化的变量是未定义的行为。
  • 关于:return l2; }; int main(){ 右大括号后的杂散分号 ; 在现代编译器上无法编译
  • @user3629249:我已经在 GCC、Clang 和 TCC 上进行了尝试,并且在所有这些上都可以正常编译。
  • 编译时,始终启用所有警告。 (对于gcc,至少使用:-Wall -Wextra -pedantic -Werror -std=gnu11)然后修复警告

标签: c pointers gcc clang tcc


【解决方案1】:

我想出了在 newList 函数和l2 -&gt; next = NULL;appendList 函数中。

但我想知道为什么输出会有所不同。有没有 编译器中的错误或者我没有初始化指向的指针是错误的 NULL 即使它在大多数编译器中都可以使用?

在没有给它赋值或导致它被显式或隐式初始化(​​这与赋值不同)的情况下访问指针的值是错误的。这样做会产生未定义的行为。在某些情况下,该程序碰巧表现出您预期的行为是一个可能且合理的结果,但它并不能验证该程序。

此外,您可能会发现您的原始方法无法在更复杂的情况下与您测试的其他编译器一起可靠地工作(但我只能对此做出概率性陈述,因为“未定义")。

【讨论】:

  • 我的错误是假设未初始化的指针默认为空,因为大多数编译器都给出了正确的输出。感谢您的帮助。
  • @AppTest-- 在 C 语言中进行假设只是自找麻烦,这可能会在您最不期望的时候表现出来。在 C 中,如果你不知道,你真的需要咨询Standard,或者至少是一个可靠的参考。
【解决方案2】:

通常在调试程序时,调试器会初始化所有内容,但在生产中没有初始化,因此下一个值不为空

初始化下一个变量。

【讨论】:

  • 调试器没有初始化任何东西。只是调试环境可能与非调试环境不同。
  • @EugeneSh。可能是,但我看到 100 次,一个未初始化的变量值作为 0 调试和执行中的随机值,我认为它是调试器,因为 0 不是随机值或临时值,但可能你是对的,它可以被“清理” " 记忆或其他。
【解决方案3】:

函数 calloc() 返回一个指向初始化为零的字节序列的指针;相比之下,malloc() 返回一个指向字节序列的指针,该字节序列可能会或可能不会碰巧最初包含零。在某些平台上,这些字节在 malloc() 之后总是包含零;在其他人身上,至少其中一些人永远不会。通常,无法预测哪些字节会保持零,哪些不会。

在大多数平台上,包括过去几十年创建的几乎所有平台,清除指针对象的所有字节会将指针设置为 NULL。在记录此类行为的平台上,使用“calloc”而不是“malloc”为包含指针的结构创建空间将是一种将其中的所有指针初始化为 NULL 的可靠方法。但是,如果使用“malloc”或“realloc”而不是“calloc”创建存储,则必须使用“memset”将所有字节设置为零,或者明确将其中包含的指针设置为NULL。

【讨论】:

    猜你喜欢
    • 2017-04-07
    • 2021-12-24
    • 2013-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-16
    相关资源
    最近更新 更多