一些 C 函数如何接受空参数?

Posted

技术标签:

【中文标题】一些 C 函数如何接受空参数?【英文标题】:How do some C functions accept null parameters? 【发布时间】:2015-02-16 09:42:20 【问题描述】:

我一直认为C不接受NULL参数,直到我开始学习指针。在某些编程语言中,例如 python,可以将 NULL 参数作为参数传递,但在 C 中,我一直认为这会导致 Undefined Behaviour

我的问题只是一个好奇,这样的函数怎么可能......

waitpid(child_pid, &status, options);  //pointer &status

...接受一个 NULL 指针作为参数而不遇到 Undefined Behaviour,难道 NULL 指针不只是指向空吗?

简单地说,为什么这在 C 中是可以接受的?

【问题讨论】:

这取决于函数的编写方式。如果存在与 NULL 指针相关的行为,为什么它会是未定义的行为? 我会说这是可取的,如果你想有无效的指针。 如果在被调用函数中取消引用空指针,它确实会导致未定义的行为。设计为接受空指针的代码将具有在使用指针之前测试指针是否为空的代码。例如,在waitpid() 中,指针可能是int *statloc,代码可能是if (statloc != NULL) *statloc = status; 它指向NULL,指针本身不是NULL。指针有一个地址。但设置为 NULL 时并不指向另一个地址。 还有一些其他的 Q/A 可能对您有所帮助。 (有点同类型。):***.com/q/11962457/1240985,***.com/q/6725809/1240985,***.com/a/1597486/1240985 【参考方案1】:

在某些编程语言中 [...] 可以将 NULL 参数作为参数传递,但在 C 中我一直认为这会导致未定义的行为。

单独为指针传递NULL 参数不会导致UB;它正在尝试访问由设置为 NULL 的指针指向的内存。

传递NULL 是在未指定某些内容的情况下非常常见的做法。调用者应在执行访问之前检查NULL 的参数。例如,标准允许您将NULL 传递给free,这使得函数更加方便。

NULL 指针不指向任何东西吗?

是的,他们有。但是“无”是全球知名的,因此使用NULL 可以让您传达一个事实,即指针指向您调用的函数。换句话说,检查

if (myPointer == NULL)

定义明确*,因此您可以利用它来发挥自己的优势。

* 除非您使用悬空指针,即您已释放的指针,或指向超出范围的对象的指针。您可以通过将NULL 分配给您free() 的每个指针来防止第一种情况的发生,通过在与自动对象的范围具有相同或更高嵌套级别的范围内声明指针来防止第二种情况发生。指针指向。

【讨论】:

“总是定义明确的”——我认为这不是真的。请在***.com/questions/26073842/…查看答案 @giorgim 你是对的,我假设指针是有效的。我在脚注中解释了这个假设。谢谢! 很高兴它有帮助;这是一个棘手的问题。为什么只检查是 UB 并不直观,但你能做什么:(【参考方案2】:
void func_with_optional_arg(char *optional)

    if (optional == NULL) 
        // do something differently
    

    /* ... */

为什么会调用 UB?取消引用 NULL 指针肯定会,但传递一个指针不会。 NULL 是一个标记值,用于确定指针是否有效(并不是说无效指针不能有其他值,但我们明确地使用了这个值。)如果将它传递给调用 UB 的函数,那么意义何在它的存在?

而传递一个 NULL 非指针值不是?

C 中没有“NULL 非指针”之类的东西,所以我不确定你的意思。

【讨论】:

:如果指针在释放后传递给它,您的 if 语句将已经调用 UB :) @giorgim:这根本不是真的。指针没有被取消引用,我们只是比较它的值,这在free 之前或之后是完全合法的。此外,还有各种调用 UB 的方法,这些方法在被调用函数中无法解释。 我觉得你搞错了,请看这里的答案:***.com/questions/26073842/… @giorgim:嗯。十年编写 C 语言,我仍在学习新事物。我想这是优化的有效案例。好在这不是我觉得需要在真实代码中做的事情。谢谢。【参考方案3】:

因为函数可以检查指针是否为 NULL 并避免使用它。一个经典的例子是一个函数,它返回一些东西作为返回值,并且可以通过指针参数提供一些额外的信息。如果调用者对此类信息不感兴趣(并且被调用者为此做好了准备),则指针参数设置为 NULL,并且被调用函数不会尝试在其指向的位置存储任何内容。

int divide(int dividend, int divisor, int *remainder=NULL) 

    if(remainder!=NULL) 
        *remainder=dividend%divisor;
    return dividend/divisor;
 

waitpid 遵循这个习惯用法:如果您不关心状态,则可以传递 NULL,避免使用虚拟变量。

一般来说,你可以使用NULL作为一个特殊的值来表示没有传递有效的指针;另一个常见的用法是对某些指针参数说“使用默认值”。

请注意,这与 Python 没有太大区别:您无法在 None 上做很多事情而不会出现错误,但您始终可以检查值是否为 None 并采取相应措施。

【讨论】:

【参考方案4】:

这完全取决于你如何处理 NULL。本质上NULL 表示值 0,因此如果您尝试将其用作整数,您应该不会有任何问题。 但是请记住,NULL 是一个定义,表示无效的内存位置(不存在),不能用作整数!

另一方面,对于指针,验证指针是否指向有效地址很重要。通常接受指针的函数必须验证传递的值是否有效,否则最终会尝试访问一些无效的内存位置并崩溃。

【讨论】:

函数如何测试传入的指针是否指向有效内存? 这取决于您希望得到答案的深度。为了简单起见,我的意思是验证指针是否为 NULL。除此之外,无法检查指针是否有效!如果您在嵌入式系统中工作,知道所有内存位置等(完全系统访问),那么您可能会保证有效的内存位置!

以上是关于一些 C 函数如何接受空参数?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过原始指针将闭包作为参数传递给 C 函数?

Dfango 函数视图 VS 类 RedirectView。如何让类视图接受参数

可空引用类型 - 通过接受的参数返回类型可空性

如何接受异步函数作为参数?

c ++:如何定义接受特定类的所有子类的函数

如何在C ++函数中返回空Mat?