C中的void类型

2024-03-08

The void从各种不同的情况来看,C 中的 type 似乎很奇怪。有时它的行为就像普通的对象类型,例如int or char,有时它毫无意义(正如它应该的那样)。

看看我的片段。首先,你可以这样做似乎很奇怪declare a void对象,意味着你什么也不声明。

然后我创建了一个int变量并将其结果转换为void,丢弃它:

如果任何其他类型的表达式被计算为 void 表达式,其值或指示符被丢弃。(ISO/IEC 9899:201x,6.3.2.2 无效)

我试图用一个来调用我的函数void演员,但我的编译器给了我(Clang 10.0):

error: too many arguments to function call, expected 0, have 1

So the void在原型中意味着nothing,而不是类型void.

但是后来,我创建了一个指向void,取消引用它,并分配“result” to my int多变的。我拿到 ”不兼容类型“ 错误。这意味着void类型确实存在于此处。

extern void a; // Why is this authorised ???

void foo(void); // This function takes no argument. Not the 'void' type.

int main(void)
{
    int a = 42;
    void *p;

    // Expression result casted to 'void' which discards it (per the C standard).
    (void)a;

    // Casting to 'void' should make the argument inexistant too...
    foo((void)a);

    // Assigning to 'int' from incompatible type 'void': so the 'void' type does exists...
    a = *p;

    // Am I not passing the 'void' type ?
    foo(*p);

    return 0;
}

Is void一个实际的类型,或者一个没有任何意义的关键字?因为有时它的行为就像指令“这里不允许任何事情”,有时就像一个真实的类型。

EDIT: 这个问题是NOT重复的。这纯粹是关于语义的void类型。我不需要任何关于如何使用的解释void, 指向void或任何其他东西。我想要一个符合 C 标准的答案。


在C语言中voidtype 的引入比“null”或“nothing”更具有“不关心”的含义,并且它用于不同的范围。

The void关键字可以引用void type, a reference to void, a void expression, a void operand or a void function。它还显式定义了一个没有参数的函数。

让我们看一下其中的一些。


The void type

首先void对象存在并具有一些特殊属性,如中所述ISO/IEC 9899:2017,§6.2.5 类型:

  1. void 类型包含一组空值;它是一个不完整的对象类型,无法完成。

Pointers

越有用的reference to void, or void *,是对不完整类型的引用,但本身定义良好,然后是完整类型,具有大小,并且可以用作任何其他标准变量,如中所述ISO/IEC 9899:2017,§6.2.5 类型:

  1. 指向 void 的指针应具有与指向字符类型的指针相同的表示和对齐要求。

    类似地,指向兼容类型的限定或非限定版本的指针应具有相同的表示和对齐要求。

    所有指向结构类型的指针应具有相同的表示和对齐要求。

    所有指向联合类型的指针应具有相同的表示和对齐要求。

    指向其他类型的指针不需要具有相同的表示或对齐要求。


投射到void

它可以用作cast使表达式无效,但允许完成任何副作用这样的表达。该概念在以下标准中进行了解释:ISO/IEC 9899:2017,§6.3 转换,§6.3.2.2 无效:

  1. void 表达式(类型为 void 的表达式)的(不存在的)值不得以任何方式使用,并且隐式或显式转换(除 void 之外)不得应用于此类表达式。

    如果任何其他类型的表达式被计算为 void 表达式,则其值或指示符将被丢弃。 (评估 void 表达式的副作用。)

铸造的实际例子void它的用途是防止函数定义中未使用的参数发出警告:

int fn(int a, int b)
{
    (void)b;    //This will flag the parameter b as used 

    ...    //Your code is here

    return 0;
}

上面的代码片段显示了用于消除编译器警告的标准做法。演员阵容void参数的b充当不生成代码和标记的有效表达式b用于防止编译器抱怨。


void功能

这段落§6.3.2.2 无效该标准,还包括一些解释void函数,即不返回表达式中可用的任何值的函数,但无论如何都会调用函数来实现副作用。


void指针属性

正如我们之前所说,指向void更有用,因为它们允许以通用方式处理对象引用,因为它们的属性在ISO/IEC 9899:2017,§6.3.2.3 指针:

  1. 指向 void 的指针可以与指向任何对象类型的指针相互转换。

    指向任何对象类型的指针都可以转换为指向 void 的指针,然后再转换回来;结果应等于原始指针.

作为实际示例,想象一个函数根据输入参数返回指向不同对象的指针:

enum
{
    FAMILY,     //Software family as integer
    VERSION,    //Software version as float
    NAME        //Software release name as char string
} eRelease;

void *GetSoftwareInfo(eRelease par)
{
    static const int   iFamily  = 1;
    static const float fVersion = 2.0;
    static const *char szName   = "Rel2 Toaster";

    switch(par)
    {
        case FAMILY:
            return &iFamily;
        case VERSION:
            return &fVersion;
        case NAME:
            return szName;
    }
    return NULL;
}

在此代码片段中,您可以返回一个依赖于输入的通用指针par value.


void作为函数参数

指某东西的用途void函数定义中的参数是在所谓的 ANSI 标准之后引入的,以有效区分具有可变参数数量的函数和具有以下参数的函数:没有参数.

从标准ISO/IEC 9899:2017, 6.7.6.3 函数声明符(包括原型):

  1. 类型的未命名参数的特殊情况void因为列表中唯一的项目指定该函数没有参数。

实际编译器仍然支持带有空括号的函数声明以实现向后兼容性,但这是一个过时的功能,最终将在未来版本的标准中删除。看未来方向 - §6.11.6 函数声明符:

  1. 使用带有空括号的函数声明符(不是原型格式参数类型声明符)是一种过时的行为 特征。

考虑以下示例:

int foo();         //prototype of variable arguments function (backward compatibility)
int bar(void);     //prototype of no arguments function
int a = foo(2);    //Allowed
int b = foo();     //Allowed
int c = bar();     //Allowed
int d = bar(1);    //Error!

现在类似于您的测试,如果我们调用该函数bar如下:

int a = 1;
bar((void)a);

触发错误,因为转换为void对象不会将其置空。所以你仍在尝试通过void对象作为没有任何函数的参数。


副作用

根据要求,这是一个简短的解释副作用概念。

副作用是指从语句执行中派生的对象和值的任何更改,这不是直接预期的效果。

int a = 0;
(void)b = ++a;

在上面的代码片段中,void 表达式失去了直接效果,赋值b,但作为副作用增加的价值a.

标准中唯一解释含义的参考文献可以在5.1.2.3 程序执行:

  1. 访问易失性对象、修改对象、修改对象 文件,或调用执行任何这些操作的函数都是 副作用,即执行状态的变化 环境。

    表达式的求值一般包括两个值 副作用的计算和启动.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C中的void类型 的相关文章

  • 创建 DirectoryEntry 实例以供测试使用

    我正在尝试创建 DirectoryEntry 的实例 以便可以使用它来测试将传递 DirectoryEntry 的一些代码 然而 尽管进行了很多尝试 我还是找不到实例化 DE 并初始化它的 PropertyCollection 的方法 我有
  • 属性对象什么时候创建?

    由于属性实际上只是附加到程序集的元数据 这是否意味着属性对象仅根据请求创建 例如当您调用 GetCustomAttributes 时 或者它们是在创建对象时创建的 或者 前两个的组合 在由于 CLR 的属性扫描而创建对象时创建 从 CLR
  • 如何在没有 Control.Invoke() 的情况下从后台线程修改控件属性

    最近 我们遇到了一些旧版 WinForms 应用程序 我们需要更新一些新功能 在专家测试该应用程序时 发现一些旧功能被破坏 无效的跨线程操作 现在 在您认为我是新手之前 我确实有一些 Windows 窗体应用程序的经验 我不是专家 但我认为
  • 嵌入式系统中的malloc [重复]

    这个问题在这里已经有答案了 我正在使用嵌入式系统 该应用程序在 AT91SAMxxxx 和 cortex m3 lpc17xxx 上运行 我正在研究动态内存分配 因为它会极大地改变应用程序的外观 并给我更多的力量 我认为我唯一真正的路线是为
  • Cygwin 下使用 CMake 编译库

    我一直在尝试使用 CMake 来编译 TinyXML 作为一种迷你项目 尝试学习 CMake 作为补充 我试图将其编译成动态库并自行安装 以便它可以工作 到目前为止 我已经设法编译和安装它 但它编译成 dll 和 dll a 让它工作的唯一
  • 为什么禁止在 constexpr 函数中使用 goto?

    C 14 对你能做什么和不能做什么有规则constexpr功能 其中一些 没有asm 没有静态变量 看起来相当合理 但标准也不允许goto in constexpr功能 即使它允许其他控制流机制 这种区别背后的原因是什么 我以为我们已经过去
  • 跨多个控件共享事件处理程序

    在我用 C 编写的 Windows 窗体应用程序中 我有一堆按钮 当用户的鼠标悬停在按钮上时 我希望按钮的边框发生变化 目前我有以下多个实例 每个按钮一个副本 private void btnStopServer MouseEnter ob
  • 如何针对 Nancy 中的 Active Directory 进行身份验证?

    这是一篇过时的文章 但是http msdn microsoft com en us library ff650308 aspx paght000026 step3 http msdn microsoft com en us library
  • C# 用数组封送结构体

    假设我有一个类似于 public struct MyStruct public float a 我想用一些自定义数组大小实例化一个这样的结构 在本例中假设为 2 然后我将其封送到字节数组中 MyStruct s new MyStruct s
  • 使用安全函数在 C 中将字符串添加到字符串

    我想将文件名复制到字符串并附加 cpt 但我无法使用安全函数 strcat s 来做到这一点 错误 字符串不是空终止的 我确实设置了 0 如何使用安全函数修复此问题 size strlen locatie size nieuw char m
  • Windows 窗体不会在调试模式下显示

    我最近升级到 VS 2012 我有一组在 VS 2010 中编码的 UI 测试 我试图在 VS 2012 中启动它们 我有一个 Windows 窗体 在开始时显示使用 AssemblyInitialize 属性运行测试 我使用此表单允许用户
  • 使用 LINQ 查找列表中特定类型的第一个元素

    使用 LINQ 和 C 在元素列表中查找特定类型的第一个项目的最短表示法是什么 var first yourCollection OfType
  • AccessViolationException 未处理

    我正在尝试使用史蒂夫 桑德森的博客文章 http blog stevensanderson com 2010 01 28 editing a variable length list aspnet mvc 2 style 为了在我的 ASP
  • 什么是 C 语言的高效工作流程? - Makefile + bash脚本

    我正在开发我的第一个项目 该项目将跨越多个 C 文件 对于我的前几个练习程序 我只是在中编写了我的代码main c并使用编译gcc main c o main 当我学习时 这对我有用 现在 我正在独自开展一个更大的项目 我想继续自己进行编译
  • EPPlus Excel 更改单元格颜色

    我正在尝试将给定单元格的颜色设置为另一个单元格的颜色 该单元格已在模板中着色 但worksheet Cells row col Style Fill BackgroundColor似乎没有get财产 是否可以做到这一点 或者我是否必须在互联
  • 在Linux中使用C/C++获取机器序列号和CPU ID

    在Linux系统中如何获取机器序列号和CPU ID 示例代码受到高度赞赏 Here http lxr linux no linux v2 6 39 arch x86 include asm processor h L173Linux 内核似
  • Bing 地图运行时错误 Windows 8.1

    当我运行带有 Bing Map 集成的 Windows 8 1 应用程序时 出现以下错误 Windows UI Xaml Markup XamlParseException 类型的异常 发生在 DistanceApp exe 中 但未在用户
  • 如何在 C# 中播放在线资源中的 .mp3 文件?

    我的问题与此非常相似question https stackoverflow com questions 7556672 mp3 play from stream on c sharp 我有音乐网址 网址如http site com aud
  • C++ 成员函数中的“if (!this)”有多糟糕?

    如果我遇到旧代码if this return 在应用程序中 这种风险有多严重 它是一个危险的定时炸弹 需要立即在应用程序范围内进行搜索和销毁工作 还是更像是一种可以悄悄留在原处的代码气味 我不打算writing当然 执行此操作的代码 相反
  • 将 viewbag 从操作控制器传递到部分视图

    我有一个带有部分视图的 mvc 视图 控制器中有一个 ActionResult 方法 它将返回 PartialView 因此 我需要将 ViewBag 数据从 ActionResult 方法传递到 Partial View 这是我的控制器

随机推荐