如果显式给出多维数组,为什么 char[][] = {{...}, {...}} 不可能?

2024-04-04

我经历了this http://helpdoco.com/C++-C/difference-between-char-pointer-and-char-array.htm文章。我理解所解释的规则,但我想知道在定义常量多维数组并直接使用给定类型的已知值对其进行初始化时,到底是什么阻止编译器接受以下语法:

const int multi_arr1[][] = {{1,2,3}, {1,2,3}}; // why not?
const int multi_arr2[][3] = {{1,2,3}, {1,2,3}}; // OK

error: declaration of 'multi_arr1' as multidimensional array must have bounds
       for all dimensions except the first

是什么阻止编译器向右查看并意识到我们正在为每个“子数组”处理 3 个元素,或者可能仅在程序员通过的情况下返回错误,例如每个子数组的元素数量不同,例如{1,2,3}, {1,2,3,4}?

例如,在处理一维字符数组时,编译器可以查看右侧的字符串=这是有效的:

const char str[] = "Str";

我想了解发生了什么,以便编译器无法推断数组维度并计算分配的大小,因为现在在我看来编译器拥有执行此操作所需的所有信息。我在这里缺少什么?


要求编译器从初始化器推断内部维度将要求编译器以标准避免的方式追溯工作。

该标准允许初始化的对象引用自身。例如:

struct foo { struct foo *next; int value; } head = { &head, 0 };

这定义了最初指向自身的链表节点。 (推测稍后会插入更多节点。)这是有效的,因为 C 2011 [N1570] 6.2.1 7 表示标识符head“其范围在其声明符完成后开始。” A声明者是声明语法的一部分,包括标识符名称以及声明的数组、函数和/或指针部分(例如,f(int, float) and *a[3]是声明符,在声明中,例如float f(int, float) or int *a[3]).

由于 6.2.1 7,程序员可以编写以下定义:

void *p[][1] = { { p[1] }, { p[0] } };

考虑初始化器p[1]。这是一个数组,因此它会自动转换为指向其第一个元素的指针,p[1][0]。编译器知道该地址,因为它知道p[i]是一个 1 的数组void *(对于任何值i)。如果编译器不知道有多大p[i]是,它无法计算这个地址。所以,如果 C 标准允许我们写:

void *p[][] = { { p[1] }, { p[0] } };

那么编译器将不得不继续扫描过去p[1]因此它可以计算为第二个维度给出的初始值设定项的数量(在本例中只有一个,但我们必须至少扫描到}看到这一点,而且可能更多),然后返回并计算p[1].

该标准避免强迫编译器执行这种多次传递工作。要求编译器推断内部维度会违反此目标,因此标准没有这样做。

(事实上​​,我认为标准可能不需要编译器做超过有限数量的前瞻,可能在标记化过程中只需要几个字符,在解析语法时只需要一个标记,但我不确定。有些事情具有直到链接时才知道的值,例如void (*p)(void) = &SomeFunction;,但这些是由链接器填充的。)

此外,考虑一个定义,例如:

char x[][] =
    {
        {  0,  1 },
        { 10, 11 },
        { 20, 21, 22 }
    };

当编译器读取前两行初始值时,它可能需要在内存中准备数组的副本。因此,当它读取第一行时,它将存储两个值。然后它看到线端,因此它可以暂时假设内部尺寸为 2,形成char x[][2]。当它看到第二行时,它会分配更多内存(与realloc)并继续,将接下来的两个值 10 和 11 存储在适当的位置。

当它读到第三行并看到22,它实现内部维度至少为三。现在编译器不能简单地分配更多内存。它必须重新排列 10 和 11 相对于 0 和 1 在内存中的位置,因为它们之间有一个新元素;x[0][2]现在存在并且值为 0(到目前为止)。因此,要求编译器推断内部维度,同时还允许每个子数组中存在不同数量的初始值设定项(并根据整个列表中看到的初始值设定项的最大数量来推断内部维度)可能会给编译器带来大量内存移动的负担。

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

如果显式给出多维数组,为什么 char[][] = {{...}, {...}} 不可能? 的相关文章

  • Java 中的 TreeSet 与 C#.net 的等效项

    我有 Java 代码 其中包含TreeSet 我想将代码转换为 C 我可以使用哪个等效集合 如果没有 请提出替代方案 那将是系统 集合 通用 SortedSet
  • VS Code:自定义关键字的注入语法范围在 C++ 中被覆盖

    我想制作一个小型 VS Code 扩展 为 C C 代码中的少数自定义关键字添加语法突出显示 我正在尝试通过注入语法来做到这一点source c and source cpp语言范围 遵循VS Code 语法高亮指南 https code
  • do { ... } while (0) — 它有什么用? [复制]

    这个问题在这里已经有答案了 我已经看到这个表情十多年了 我一直在努力思考它有什么好处 因为我主要在 defines 中看到它 所以我认为它对于内部作用域变量声明和使用中断 而不是 gotos 很有用 对其他方面有好处吗 你用它吗 这是 C
  • 我应该如何以非 root 身份读取 Linux 上的 Intel PCI 非核心性能计数器?

    我想要一个库 允许对 Linux 可执行文件的关键部分进行 自我分析 就像人们可以使用一个部分计时一样获取当日时间 http linux die net man 2 gettimeofday or RDTSC http www strchr
  • 如何从 C# 可移植类库 (PCL) 添加对 F# 可移植库的引用

    我有一个项目 其中包含两个 F 项目和一个 C 项目 我想在其中编写一些 XUnit 测试 FS PL F 3 1 3 3 1 0 可移植库 FS PL Legacy F 31 2 3 5 1 可移植库 旧版 测试 C NET 4 5 Wi
  • 获取在 Unity 中实现接口的所有类型

    如果您只想知道解决方案 请跳至更新 我有一个应用程序 它使用以下代码来获取并运行许多工作方法 var type typeof IJob var types AppDomain CurrentDomain GetAssemblies Sele
  • 如何将带有自定义标头的任意 JSON 数据发送到 REST 服务器?

    TL DR 如何将 JSON 字符串发送到带有 auth 标头的 REST 主机 我尝试了 3 种不同的方法 发现一种适用于匿名类型 为什么我不能使用匿名类型 我需要设置一个名为 Group Name 的变量 并且连字符不是有效的 C 标识
  • SQL 选择与带有通配符的 URL 匹配的行

    我在数据库中有一个表 其中一列包含一个 URL 例如http example com users http example com users 轮廓 我得到了一个 URL 例如http example com users 234 profi
  • 重写 ASP.Net Core 中的 415 响应

    在 ASP net Core 2 1 中 我想返回 Json 响应以及状态代码 415 而不是默认返回的 415 为了实现这一点 我使用资源过滤器 public class MediaTypeResouceFilter Attribute
  • Err_Response_Headers_Multiple_Content_Disposition

    我需要导出 2csv单击一个按钮即可打开文件 下面是我生成2的代码csv files using System Data using System Data SqlClient using System Text using System
  • GridView必须添加到表单标签中才能渲染

    TextWriter tr new StringWriter HtmlTextWriter writer new HtmlTextWriter tr HtmlForm form new HtmlForm form Controls Add
  • Time 方法在另一个线程中执行并在超时时中止

    您好 我正在尝试异步运行方法 以便计算持续时间并在超过超时时取消该方法 我尝试使用异步和等待来实现这一点 但没有运气 也许我过度设计了这个 任何输入都会受到赞赏 应该注意的是 我无法更改接口 TheirInterface 因此得名 到目前为
  • 了解C/C++中函数调用的堆栈框架? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我也是 C C 和汇编语言的新手 这
  • std::regex 的行为不一致

    我有以下问题 std regex如果我传递结果 行为会有所不同boost filesystem path string vs 将结果存储在中间字符串变量中 第一个将返回一个被截断的匹配 并且稍后不被接受std stoull 抛出 inval
  • CGAL:如何有效计算多面体的面面积?

    我有一个多面体 其面是三角形 我知道在 CGAL 中 Triangle 3 类提供了 squared area 方法 通过它我们可以计算三角形的面积 有什么方法可以将其应用到多面体方面吗 或者关于如何计算每个面的面积有什么想法吗 这是一个例
  • 在信号/槽处理期间删除 QObject

    我知道从槽处理中删除 QObject 可能会使应用程序崩溃 因为它可能有其他排队的事件 因此 我将使用 obj gt deleteLater 而不是使用 delete obj 据我所知 obj 等待处理所有排队的事件 然后 删除 obj Q
  • 如何使 RSACryptoServiceProvider 在没有填充(nopadding)的情况下工作?

    我需要使 C 应用程序与 Java 应用程序兼容 Java 应用程序使用Cipher getInstance RSA ECB nopadding 初始化器使密码 ECB 和无填充 但是 在 C 中 您有 2 个填充选项 OAEP 填充或 P
  • ASP .NET Core IIS 托管用户身份名称为空且 IsAuthenticated=false

    我在 IIS 上运行 ASP NET Core dll 使用 AspNetCoreModule 使用以前的 ASP NET 我可以通过以下方式获取用户身份名称 HttpContext Current User Identity Name 因
  • 使用抽象类作为模板类型

    我对c 还是很陌生 来自java 我有一个 stl 类型列表Actor When Actor仅包含 真实 方法就没有问题 我现在想将这个类扩展到几个类 并且需要将一些方法更改为抽象的 因为它们不再具有具体的意义 正如我 从文档中 预期的那样
  • Microsoft Graph API 调用无限期挂起

    我正在尝试使用 Microsoft Graph 查询 Azure Active Directory 用户信息 我可以很好地进行身份验证 但是当我尝试查询用户信息时client Users我的应用程序无限期挂起 没有超时 没有错误 只是挂起

随机推荐