当前位置: 首页 > 知识库问答 >
问题:

C中如何处理常量结构成员?

公孙阳羽
2023-03-14

做这样的事情可以吗?

struct MyStruct {
    int x;
    const char y; // notice the const
    unsigned short z;
};
struct MyStruct AStruct;
fread(&MyStruct, sizeof (MyStruct), 1,
      SomeFileThatWasDefinedEarlierButIsntIncludedInThisCodeSnippet);

我正在通过从文件写入整个结构来更改常量结构成员。应该如何处理这个问题?如果一个或多个结构成员是常量,则写入非常量结构是未定义的行为吗?如果是这样,处理常量结构成员的公认做法是什么?

共有3个答案

白君之
2023-03-14

标准对“对象”一词的定义和使用有点草率。对于像“所有X都必须是Y”或“没有X可能是Z”这样的陈述来说,要有意义,X的定义必须有不仅所有X都满足的标准,而且要明确排除所有不需要是Y或允许是Z的对象。

然而,“对象”的定义只是“执行环境中的数据存储区域,其内容可以表示值”。然而,这样一个定义并不能清楚地说明,连续地址的每个可能范围是否总是一个“对象”,或者各种可能的地址范围何时受到适用于“对象”的限制,何时不受限制。

为了使《标准》明确地将角落案例分为已定义或未定义,委员会必须就其是否应定义达成共识。如果委员会成员对某些案件是否应该定义存在根本性分歧,那么通过协商一致通过规则的唯一方法是,如果规则的书写方式模棱两可,使得对应该定义什么持有矛盾观点的人认为规则支持他们的观点。虽然我不认为委员会成员明确希望他们的规则模棱两可,但我认为委员会不可能就不明确的规则达成共识。

在这种情况下,许多操作,包括更新具有固定成员的结构,很可能属于标准不要求实现有意义地处理,但标准作者希望实现无论如何都会有意义地进行处理的操作领域。

白昊乾
2023-03-14

阅读 C11 标准 n1570 及其与常量限定符相关的 §6.7.3。

如果是,处理常量结构成员的公认做法是什么?

这取决于您是更关心严格遵守C标准,还是更关心实际的实现。参见讨论这些问题的报告草案(2020年6月工作进展中)。这些考虑取决于分配给项目的开发工作,以及软件的可移植性(到其他平台)。

你很可能不会在Covid呼吸器的嵌入式软件(或一些洲际弹道导弹内部)和廉价消费电器内部或运行在一些廉价租赁的Linux虚拟处理器上的网络服务器(如lighttpd或libonion等库或一些FastCGI应用程序)上花费同样的精力。

也可以考虑在代码上使用静态分析工具,如Frama-C或Clang静态分析器。

关于未定义的行为,请务必阅读此博客。

另见对相关问题的答复。

我正在通过从文件写入整个结构来更改常量结构成员。

然后,endpoint问题和文件系统问题很重要。考虑使用与JSON、YAML相关的库,或者与sqlite、PostGreSQL或TokyoCabinet混合使用(所有这些开源库的源代码,或者来自Linux内核的源代码可能会很有启发性)。

岳正浩
2023-03-14

这是未定义的行为。

C11草案n1570说:

6.7.3类型限定符

如果尝试通过使用具有非 const 限定类型的左值来修改使用 const 限定类型定义的对象,则该行为是未定义的。

我对此的解释是:为了符合标准,您只能在对象创建(又名初始化)期间设置const成员的值,例如:

struct MyStruct AStruct = {1, 'a', 2};  // Fine

在做

AStruct.y = 'b';   // Error

应该给出一个编译器错误。

您可以使用以下代码欺骗编译器:

memcpy(&AStruct, &AnotherStruct, sizeof AStruct);

它可能在大多数系统上都能正常工作,但根据C11标准,它的行为还没有定义。

另请参阅目标指针指向常量数据的memcpy

 类似资料:
  • 问题内容: 我知道callable的调用可能会将异常抛出给调用它的父方法,而runnable则不是这种情况。 我不知道如何,因为它是线程方法,并且是线程堆栈的最底层方法。 问题答案: 的要点是将异常抛出到调用线程,例如,当您获得提交的结果时。

  • 主要内容:try/catch语句,C#中的异常类,自定义异常类,抛出异常在 C# 中,异常是在程序运行出错时引发的,例如以一个数字除以零,所有异常都派生自 System.Exception 类。异常处理则是处理运行时错误的过程,使用异常处理可以使程序在发生错误时保持正常运行。 C# 中的异常处理基于四个关键字构建,分别是 try、catch、finally 和 throw。 try:try 语句块中通常用来存放容易出现异常的代码,其后面紧跟一个或多个 catch 语句

  • 异常是程序在执行期间产生的问题。C++ 异常是指在程序运行时发生的特殊情况,比如尝试除以零的操作。 异常提供了一种转移程序控制权的方式。C++ 异常处理涉及到三个关键字:try、catch、throw。 throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。 catch: 在您想要处理问题的地方,通过异常处理程序捕获异常。catch 关键字用于捕获异常。 try

  • 使用符合03标准的编译器(gcc-3.3.2的安全关键变体)。该标准规定必须定义静态成员对象(9.4.2(4))。它还规定“一个定义”规则适用,但不需要诊断(9.4.2(5))。以下代码有效吗? 也就是说,没有“静态常量int fred::JOE;”。我这样问是因为我们有一个例子(显然),模板类中的静态常量从未定义过,代码在某些上下文中工作,但在其他上下文中不工作。我用一个枚举替换了静态常量int

  • 我试图声明一个const闭包,以便在我的代码中使用: 但是我遇到了编译时不知道大小的问题。 我也试过: 但它说必须知道的类型。 定义一个泛型结构里面有一个泛型结构吗?

  • 本文向大家介绍C++中的常量定义小结,包括了C++中的常量定义小结的使用技巧和注意事项,需要的朋友参考一下 本篇笔记总结自一次代码检视。 一般来说,使用C语言编程时我们都习惯在代码当中使用C当中的宏定义来定义一个数值常量: 在C++开发项目时,也会经常存在沿袭C当中常量用法情况。所以,如下的一种写法看起来反倒觉得有些不正宗了: 站在编译器的角度,这两种写法都是合法的,但在使用的时候总得二中择一,究