为什么写'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