在c(或c ++)中,有什么区别
char myarr[16]={0x00};
和
char myarr[16]; memset(myarr, '\0', sizeof(myarr));
??
编辑:我问这个是因为在vc ++ 2005中结果是一样的..
编辑更多:和
char myarr[16]={0x00,};?
Joh*_*itb 18
重要的区别在于第一个默认值以特定于元素的方式初始化数组:指针将接收空指针值,该值不需要是0x00(如在所有位中为零),布尔值将为false.如果元素类型是不是所谓的POD(普通旧数据类型)的类类型,那么你只能做第一个,因为第二个只适用于最简单的情况(你没有虚拟的情况)函数,用户定义的构造函数等).相反,使用memset的第二种方法是将数组的所有元素设置为全位 - 零.这并不总是你想要的.例如,如果您的数组有指针,则它们不会被设置为空指针.
第一个将默认初始化数组的元素,第一个元素除外,它显式设置为0.如果数组是本地的并且在堆栈上(即,不是静态的),编译器内部通常会执行memset来清除数组.如果阵列是非本地或静态的,则第一个版本可以更高效.编译器可以在编译时将初始化程序放入生成的汇编程序代码中,使其根本不需要运行时代码.或者,当程序以快速方式(即逐页)启动时,阵列可以布置在自动归零的部分(对于指针,如果它们具有全比特零表示).
第二个在整个数组上明确地做了一个memset.优化编译器通常会使用内联机器代码替换较小区域的memset,这些机器代码只使用标签和分支进行循环.
这是为第一种情况生成的汇编程序代码.我的gcc内容没有太多优化,所以我们得到了一个真正的memset调用(堆栈顶部的16个字节总是分配,即使我们没有本地.$ n是寄存器号):
void f(void) {
int a[16] = { 42 };
}
sub $29, $29, 88 ; create stack-frame, 88 bytes
stw $31, $29, 84 ; save return address
add $4, $29, 16 ; 1st argument is destination, the array.
add $5, $0, 0 ; 2nd argument is value to fill
add $6, $0, 64 ; 3rd argument is size to fill: 4byte * 16
jal memset ; call memset
add $2, $0, 42 ; set first element, a[0], to 42
stw $2, $29, 16 ;
ldw $31, $29, 84 ; restore return address
add $29, $29, 88 ; destroy stack-frame
jr $31 ; return to caller
Run Code Online (Sandbox Code Playgroud)
来自C++标准的血腥细节.上面的第一个案例将默认初始化剩余的元素.
8.5
:
为类型为T的对象零初始化存储意味着:
- 如果T是标量类型,则将存储设置为0(零)转换为T的值 ;
- 如果T是非联合类类型,则每个非静态数据成员和每个基类子对象的存储都是零初始化的;
- 如果T是联合类型,则其第一个数据成员的存储是零初始化的;
- 如果T是数组类型,则每个元素的存储都是零初始化的;
- 如果T是引用类型,则不执行初始化.
默认初始化T类型的对象意味着:
- 如果T是非POD类类型,则调用T的默认构造函数
- 如果T是数组类型,则每个元素都是默认初始化的;
- 否则,对象的存储被零初始化.
8.5.1
:
如果列表中的初始值设定项少于聚合中的成员,则未明确初始化的每个成员都应默认初始化(8.5).
Chr*_*oph 16
ISO/IEC 9899:TC3 6.7.8,第21段:
如果括号括起的列表中的初始值设定项少于聚合的元素或成员,或者用于初始化已知大小的数组的字符串文字中的字符数少于数组中的元素,则聚合的其余部分应为隐式初始化与具有静态存储持续时间的对象相同.
具有静态存储持续时间的数组被初始化为0
,因此C99规范保证未显式初始化的数组元素也被设置0
为.
在我对这篇文章的第一次编辑中,我喷出了一些关于在初始化后使用复合文字分配给数组的废话.这不起作用.如果您真的想使用复合文字来设置数组的值,则必须执行以下操作:
#define count(ARRAY) (sizeof(ARRAY)/sizeof(*ARRAY))
int foo[16];
memcpy(foo, ((int [count(foo)]){ 1, 2, 3 }), sizeof(foo));
Run Code Online (Sandbox Code Playgroud)
使用一些宏魔术和非标准__typeof__
运算符,可以大大缩短:
#define set_array(ARRAY, ...) \
memcpy(ARRAY, ((__typeof__(ARRAY)){ __VA_ARGS__ }), sizeof(ARRAY))
int foo[16];
set_array(foo, 1, 2, 3);
Run Code Online (Sandbox Code Playgroud)
也许char myarr[16]={0x00};
这不是一个很好的例子,因为显式和隐式成员初始化都使用零,这使得解释在这种情况下发生的事情变得更加困难。我认为现实生活中具有非零值的示例可能更能说明问题:
/**
* Map of characters allowed in a URL
*
* !, \, (, ), *, -, ., 0-9, A-Z, _, a-z, ~
*
* Allowed characters are set to non-zero (themselves, for easier tracking)
*/
static const char ALLOWED_IN_URL[256] = {
/* 0 1 2 3 4 5 6 7 8 9*/
/* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 20 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 30 */ 0, 0, 0, '!', 0, 0, 0, 0, 0, '\'',
/* 40 */ '(', ')', '*', 0, 0, '-', '.', 0, '0', '1',
/* 50 */ '2', '3', '4', '5', '6', '7', '8', '9', 0, 0,
/* 60 */ 0, 0, 0, 0, 0, 'A', 'B', 'C', 'D', 'E',
/* 70 */ 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
/* 80 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
/* 90 */ 'Z', 0, 0, 0, 0, '_', 0, 'a', 'b', 'c',
/* 100 */ 'd', 'e', 'f', 'g' , 'h', 'i', 'j', 'k', 'l', 'm',
/* 110 */ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
/* 120 */ 'x', 'y', 'z', 0, 0, 0, '~',
};
Run Code Online (Sandbox Code Playgroud)
这是一个可在对字符串进行 URL 编码时使用的查找表。仅将 URL 中允许的字符设置为非零值。零表示不允许使用该字符,需要对其进行 URL 编码 ( %xx
)。请注意,表格在波浪号字符后面突然以逗号结尾。波浪号后面的任何字符都是不允许的,因此应设置为零。但是,我们没有编写更多的零来填充表中最多 256 个条目,而是让编译器将其余条目隐式初始化为零。