为什么写'sizeof(char)`如果字符是1是标准的?
我正在做一些C编码,阅读了一些C代码后,我注意到有代码片段
char *foo = (char *)malloc(sizeof(char) * someDynamicAmount);
所以我想问问什么更多的C – ISH方式来分配char数组的内存? 使用sizeof(char)
并假定代码是针对任何标准更改的代码,或省略它并直接使用该数字?
更Cish的方式将是
char* foo = malloc(someDynamicAmount * sizeof *foo);
引用variables而不是types,以便不需要types。 而没有投下malloc(这是C + + ish)的结果。
我做sizeof(char)
来使意图清晰。 如果有人决定他希望foo是一个int
他知道他需要做sizeof(int)
来继续工作。
或省略它并使用该号码
另外使用幻数不是很好的编码习惯。
恕我直言,最好的做法是写sizeof(*foo)
。 那么如果foo的types改变,并且sizeof没有被修正,那么你也被覆盖了。
比较:
float*baz = malloc(sizeof(float) * someDynamicAmount); int *bar = malloc(sizeof(int) * someDynamicAmount); char *foo = malloc(sizeof(char) * someDynamicAmount);
VS:
float*baz = malloc(sizeof(float) * someDynamicAmount); int *bar = malloc(sizeof(int) * someDynamicAmount); char *foo = malloc(someDynamicAmount);
我喜欢第一个版本。 你喜欢第二个?
你是正确的,按照标准,乘法是不相关的。 也就是说,这看起来像是一个人习惯于保持一致的习惯。 如果你总是使用sizeof()
,不pipetypes如何,你永远不会忘记。
char *foo = (char *)malloc(sizeof(char) * someDynamicAmount); int *bar = (int *)malloc(sizeof(int) * someDynamicAmount);
常用的习语是
T *p = malloc(N * sizeof *p);
要么
T *p; ... p = malloc(N * sizeof *p);
这样你就不必担心types。
引用C99标准 ,第6.5.3.4节运算符的sizeof
:
当应用于具有char,unsigned char或signed char的操作数(或其合格版本)时, 结果为1 。 当应用于具有数组types的操作数时,结果是数组中的总字节数。 应用于具有结构或联合types的操作数时,结果是此类对象中的总字节数,包括内部和尾部填充。
也就是sizeof char == 1
的标准,而不是实现。 因此,在为char和malloc()
调用类似的情况下,省略sizeof(char)
是绝对正确的。 恕我直言,这是非常不可能的,未来的C标准将允许实现特定大小的char
,因为太多的代码已经取决于它是1,向后兼容性是非常重要的C.
因此,问题只是风格,而不是正确,我在这里支持AProgrammer的答案 。
写入sizeof(char)
并不能防止代码对抗标准中可能发生的变化。 这通常是完全误解了C语言中sizeof
意义和整个memory对象的基本模型 – C语言中所谓的types表示 。 sizeof
运算符甚至存在或有意义的唯一原因是因为C指定对象在内存中具有unsigned char
的最小可能单位的“表示”。 如果不是这样,存储将是更抽象的,将不会使用sizeof
和相关的指针算术。
sizeof
是以char
为单位定义的 ,即sizeof(T)==N
表示typesT
占用N
char
。 鉴于此, sizeof(char)
是完全愚蠢的; 它正在尝试测量有多less个char
占据char
。
这都是编码风格的问题。 存在几种样式。
为了回答这个问题,人们写道
malloc(n * sizeof(char))
保持所有使用malloc
的代码一致。 下一次他们可能需要int
,然后他们可以用相同的方式编写代码,
malloc(n * sizeof(int))
所以这样做是为了保持编码风格的一致性。 即使sizeof(char)
的确保证总是1,因此也是多余的。 这是编写自我logging代码的一种方法。
然而,在C中使用malloc最常用的方法也许是
type* t = malloc(n * sizeof(*t));
或100%等同:
type* t = malloc(n * sizeof *t);
由于sizeof
的运算符没有对副作用进行评估,因此即使variablest
尚未初始化,此代码也是安全的。
第三种可能的风格是正确的,使用数组指针 ,因为我们分配的实际上是数组:
type (*t)[n] = malloc( sizeof(type[n]) );
就types正确性而言,这也许是最正确的方法。 一个数组的大小被分配,我们用一个数组指针指向分配的数组。
然而,这种风格的问题在于数组指针为语法增加了额外的复杂性:您必须将此数组取消为(*t)[i]
而不是t[i]
。 它使代码更难阅读。 (另外,如果n不是一个整型常量expression式,那么代码就不能在旧的,过时的C编译器上编译)。
编码风格也可以写成:
char *foo = (char *)malloc(1 * someDynamicAmount);
但是这样做是为了根据所需的基本数据types的数量来增加dynamic分配内存。 如果你想增加100个字符,它会增加100个字符。 如果可能没有必要,但如果我们写101或102这样做会浪费内存。 根据基本数据types来做它不会浪费任何内存空间
该标准故意模糊了常见types的大小。 [ Wikipedia ]
尽pipechar
的大小不会改变,但short
的大小已经改变。 惯用的方式是:
type_t *foo = malloc(sizeof(type_t) * someDynamicAmount);
对于任何types(公共或复杂)的type_t或
type_t *foo = malloc(sizeof(*foo) * someDynamicAmount);
因此,您可以决定稍后更改foo的types,只能在一个地方更改。
想想unicode和多字节string。 如果char表示string中的单个字符,它实际上可能占用多个字节,导致sizeof()> 1