【问题标题】:What is an undefined vector element represented as in memory?什么是内存中表示的未定义向量元素?
【发布时间】:2020-04-02 20:07:59
【问题描述】:

我目前正在学习 C,我有一个问题,我必须猜测内存中的值。 当我说,例如long var1[1243] = {10, 1, 0, -1, -10} 并定义这个向量时,它的前 5 个元素已经定义,但是代表剩余 1238 个元素的分配字节,它们在内存中设置了什么?更具体地说,它们是 0 吗?会说,在汇编中,在定义它们之后,.zero <number of remaining bytes in vector> 正确吗?

【问题讨论】:

  • 如果提供了任何初始化程序,其余元素将设置为零。请参阅 ISO/IEC 9899:2011 §6.7.9 ¶21。
  • 我在这里相对较新,我不完全确定如何将 2 个答案标记为正确,但 @fuz 和 Fire Lancer 都告诉我我想要什么,并增加了一些知识。谢谢!
  • @Hasake。很快你就会有足够的代表来投票,这是你应该对所有你认为有用或好的问题和答案做的事情。由于您只有一个评论和一个答案,因此您只能选择答案,在这种特殊情况下选择微不足道。
  • “很快”的意思是“在我完成打字之前”。干得好。
  • @Hasake 您只能将一个答案标记为已接受。但是,您可以随时为您喜欢的答案投票。

标签: arrays c assembly initialization


【解决方案1】:

通过至少初始化一些元素{10}C 将初始化数组中的所有剩余元素,就像一个全局变量一样。数字零或空指针取决于类型,在结构数组的情况下,结构的所有成员递归。

在 C++ 中,空的初始化器也可以工作 long var1[1243] = {},但这在 C 中是不允许的。

【讨论】:

  • @fuz 我认为int I{}; 样式语法是本意。
  • @TanveerBadar 我删除了我的评论,因为 C 语法确实没有 type declarator = {} 的产生式。这是因为花括号必须始终包含至少一个初始化程序。
  • 看起来GCC默认允许= {},“警告:ISO C禁止空初始化大括号[-Wpedantic]”
  • 感谢大家的澄清和补充讨论!正是我需要的。 :)
【解决方案2】:

为什么不试试呢?

long var1[1243] = {10, 1, 0, -1, -10};

long so ( unsigned int x )
{
    long var2[1243] = {10, 1, 0, -1, -10};
    return(var2[x]);
}

编译和反汇编

Disassembly of section .text:

00000000 <so>:
   0:   e92d4010    push    {r4, lr}
   4:   e24ddd4d    sub sp, sp, #4928   ; 0x1340
   8:   e24dd030    sub sp, sp, #48 ; 0x30
   c:   e1a04000    mov r4, r0
  10:   e3a01000    mov r1, #0
  14:   e59f203c    ldr r2, [pc, #60]   ; 58 <so+0x58>
  18:   e28d0004    add r0, sp, #4
  1c:   ebfffffe    bl  0 <memset>
  20:   e3a0000a    mov r0, #10
  24:   e3a01001    mov r1, #1
  28:   e3e02000    mvn r2, #0
  2c:   e3e03009    mvn r3, #9
  30:   e98d0003    stmib   sp, {r0, r1}
  34:   e58d3014    str r3, [sp, #20]
  38:   e58d2010    str r2, [sp, #16]
  3c:   e28d3e37    add r3, sp, #880    ; 0x370
  40:   e0830104    add r0, r3, r4, lsl #2
  44:   e510036c    ldr r0, [r0, #-876] ; 0xfffffc94
  48:   e28ddd4d    add sp, sp, #4928   ; 0x1340
  4c:   e28dd030    add sp, sp, #48 ; 0x30
  50:   e8bd4010    pop {r4, lr}
  54:   e12fff1e    bx  lr
  58:   0000136c    andeq   r1, r0, r12, ror #6

Disassembly of section .data:

00000000 <var1>:
       0:   0000000a    andeq   r0, r0, r10
       4:   00000001    andeq   r0, r0, r1
       8:   00000000    andeq   r0, r0, r0
       c:   ffffffff            ; <UNDEFINED> instruction: 0xffffffff
      10:   fffffff6            ; <UNDEFINED> instruction: 0xfffffff6
    ...

要确认 ... 如果我链接它,那么我会在 .data 中看到零:

00000000  10 40 2d e9 4d dd 4d e2  30 d0 4d e2 00 40 a0 e1  |.@-.M.M.0.M..@..|
00000010  00 10 a0 e3 3c 20 9f e5  04 00 8d e2 0e 00 00 eb  |....< ..........|
00000020  0a 00 a0 e3 01 10 a0 e3  00 20 e0 e3 09 30 e0 e3  |......... ...0..|
00000030  03 00 8d e9 14 30 8d e5  10 20 8d e5 37 3e 8d e2  |.....0... ..7>..|
00000040  04 01 83 e0 6c 03 10 e5  4d dd 8d e2 30 d0 8d e2  |....l...M...0...|
00000050  10 40 bd e8 1e ff 2f e1  6c 13 00 00 1e ff 2f e1  |.@..../.l...../.|
00000060  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001000  0a 00 00 00 01 00 00 00  00 00 00 00 ff ff ff ff  |................|
00001010  f6 ff ff ff 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00001020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
0000236c

因此,对于本地和全局版本,gcc 至少是零填充其余部分。但正如评论中指出的那样,您应该看到规范,仅仅因为一个编译器没有,这并不意味着它应该如何工作或总是工作。

【讨论】:

  • 为什么不试试呢? 可能因为这并不能告诉你它是实现细节还是语言规则。不是我的反对意见,但您至少应该包括它得到保证的事实,并且只显示反汇编以查看编译器如何选择实现自动存储的初始化。
  • 如果它没有将其归零,那么它会告诉您一些信息,如果它确实如此,那么您检查规范。它还告诉您实现产生了什么。从两端点燃蜡烛以更快地到达中间。
  • 这是一个公平的观点;如果您在回答中这么说,我会投赞成票。
  • 与其他未初始化的本地项一样,我希望函数中的数组仅初始化少数项,其余项在内存中发现是陈旧/垃圾。通过尝试,我也学到了一些东西......不要认为编译器会添加这样的代码只是为了好玩,实现定义,所以假设不看它的规范......我不写这样的代码所以不必担心,并且/ 或者现在绝对可以避免这样的代码。
  • 这里的另一个学习经验是如何编写像这样的简单函数来演示一些东西而不会被优化掉。操作编译器需要(大量)练习,但不仅对仅用于演示编译器如何处理某些事情的简单无用函数有很大好处。
猜你喜欢
  • 2012-11-15
  • 2019-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-14
  • 2014-04-14
  • 2021-10-15
  • 1970-01-01
相关资源
最近更新 更多