是什么解释了C编译器w.r.t字符串初始化的这种行为?

时间:2016-12-07 22:46:18

标签: c arrays string buffer-overflow

以下代码不会生成空终止符

Random roll = new Random();
int [,] dieValue1 = new int[7, 7];
int[,] dieValue2 = new int[7, 7];
int die1 = 0;
int die2 = 0;
int die3 = 0;
int die4 = 0;
die1 = roll.Next(6);
die2 = roll.Next(6);
die3 = roll.Next(6);
die4 = roll.Next(6);
lblDice1.ImageIndex = die1;
lblDice2.ImageIndex = die2;
//die roll for the first list
for (int rollNum = 1; rollNum< 51; rollNum++)
{
    die1 = roll.Next(1, 7);
    die2 = roll.Next(1, 7);
    dieValue1[die1, die2] += 1; 
    lstRolls.Items.Add("Roll " + rollNum + " : " + "die 1 is a " + die1 + ", " + "die 2 is a " + die2);
}
//die roll for the second list 
for (int rollNum1 = 1; rollNum1< 51; rollNum1++)
{                
    die3 = roll.Next(1, 7);
    die4 = roll.Next(1, 7);
    dieValue2[die3, die4] += 1;
    lstRolls2.Items.Add("Roll " + rollNum1 + " : " + "die 3 is a " + die3 + ", " + "die 4 is a " + die4);
}
for (int r = 1; r < 51; r++)
{
    lstRollDifference.Items.Add("First rolls :" + dieValue1 + " " + "Second rolls :" + dieValue2);
}

参见拆卸装置的相关部分

/* Case 1 */
#include <stdio.h>
void main () {
    char wbuf[16] = "0123456789abcdef";
    printf("%s\n", wbuf);
}

以下代码生成一个:

0x4005b4 <main+23>:  movabs $0x3736353433323130,%rax
0x4005be <main+33>:  mov    %rax,-0x20(%rbp)
0x4005c2 <main+37>:  movabs $0x6665646362613938,%rax
0x4005cc <main+47>:  mov    %rax,-0x18(%rbp)
0x4005d0 <main+51>:  lea    -0x20(%rbp),%rax --->prinft related
0x4005d4 <main+55>:  mov    %rax,%rdi
0x4005d7 <main+58>:  callq  0x400470 <puts@plt>

再次查看拆卸组件的相关部分

/* Case 2 */
#include <stdio.h>
void main () {
    char wbuf[17] = "0123456789abcdef";
    printf("%s\n", wbuf);
}

我会假设像0x4005b4 <main+23>: movabs $0x3736353433323130,%rax 0x4005be <main+33>: mov %rax,-0x20(%rbp) 0x4005c2 <main+37>: movabs $0x6665646362613938,%rax 0x4005cc <main+47>: mov %rax,-0x18(%rbp) 0x4005d0 <main+51>: movb $0x0,-0x10(%rbp) >>>>>> Null terminator comes here 0x4005d4 <main+55>: lea -0x20(%rbp),%rax --->prinft related 0x4005d8 <main+59>: mov %rax,%rdi 0x4005db <main+62>: callq 0x400470 <puts@plt> 这样的字符串初始化来添加空终止符,就像在第二种情况下一样。但是,以下问题仍然存在:

  1. 为什么编译器不会在第一种情况下警告&#34;初始化时间过长&#34; 比默默地避免空终止符。还有一个字符如char wbuf[xxx] = "yyyy"触发警告:字符数组的初始化字符串太长
  2. 这种行为会在编译器中发生变化吗?我正在使用 gcc ubuntu 并正在使用 O0 选项进行编译
  3. 为什么它在1和2中表现不一致,例如它可能有 在case1中盲目地写了16,并添加了Null终结符?
  4. `

2 个答案:

答案 0 :(得分:6)

关于初始化的C11 standard部分6.7.9(强调我的):

  

字符类型数组可以由字符串初始化   文字或UTF-8字符串文字,可选择用大括号括起来。   字符串文字的连续字节(包括终止空值)   字符如果有空间或数组的大小未知)   初始化数组的元素。

因此编译器完全符合规范。

答案 1 :(得分:2)

在C语言char中,带有字符串文字初始值设定项的数组可用于定义常规的以零结尾的字符串以及所谓的固定宽度字符串(请参阅difference fixed width strings and zero-terminated strings )。固定宽度字符串的想法在很大程度上被遗忘了,但它在C语言和Unix OS的早期阶段发挥了作用。

固定宽度字符串约定允许例如8 char的数组包含长度为8的固定宽度字符串(没有零终结符)

char fws_hello[8] = "Hello!!!";
/* `fws_hello` is a valid fixed-width string for width 8 */

支持此类字符串的语言很可能是使用终止零“从数组末尾掉落”的权限。

另一种语言功能 - 全有或全无的初始化方法 - 也可视为满足固定宽度字符串的需求

char fws_hi[8] = "Hi";
/* `fws_hi` is padded with zeros all the way to the very end of 
    the array, which makes it a valid fixed-width string for width 8 */

我猜C ++不再需要这样的字符串格式,这使得它能够收紧初始化规则并防止终止零丢失。