无法解释此 C 代码片段的行为

Can't explain the behavior of this C code snippet

查看以下代码片段:

int len = -2;
char* buff = (char*) malloc(len+4);
if (len > sizeof(buff))
    puts("ERROR!");
else
    puts("OK!");

使用 GCC 4.8.2 在 Ubuntu-14.04(64 位)上编译和 运行 此代码打印 ERROR.

我使用以下代码打印了 lensizeof(buf) 的值:

printf("len = %d, size = %lu", len, sizeof(buff));

并打印:

len = -2, size = 8

更改 len 的值对 sizeof(buff) 的值没有影响,即使是正值 len

如果我没记错的话,值8是我64位机器上指针地址的长度,无论我给malloc什么,它都是不变的。如果是这样,我有两个问题:

1)为什么上面的if语句打印的是ERROR? (因为 -2 不大于 8 !!)

2)为什么下面的代码不打印8?

char array[10];
printf("%lu", sizeof(array));

此代码打印数组的长度。 char[]mallocchar* 有什么区别?我知道前者是在栈上分配的,后者是在堆上动态分配的,但不管怎么说都是系统内存的指针地址。我不明白 sizeof 相对于 char[]char* 来自 malloc 的不同行为!好像不一致!

你的代码有什么问题?

int len = -2;
char* buff = (char*) malloc(len+4); /* don't cast malloc not wrong, but might hide bugs. */
if (len > sizeof(buff)) /* sizeof() is unsigned and len is signed */
    puts("ERROR!");
else
    puts("OK!");

您将 signed 值与 unsigned 值进行比较,并且由于 unsigned wrap around

unsigned int x = -1;

那么 x > 0 总是正确的,并且几乎可以肯定 x > len + 4 我认为这是你想要比较的,但 x > sizeof(char *) 肯定是 x > sizeof(buff) 的意思你的情况。

此外,sizeof() 给出了类型的大小,在你的情况下,因为 buff 是一个指针,所以它是指针的大小,让代码工作这样做

使用gcc警告,它会告诉你signedunsigned比较。

gcc -Wall -Wextra -Werror

注意,-Werror 会将警告视为错误,并在发出警告时中止编译。

如果你想测试这个,就这样试试

int len = -2;
char* buff = (char*) malloc(len+4); /* don't cast malloc not wrong, but might hide bugs. */
if (len > (int)sizeof(buff)) /* sizeof() is unsigned and len is signed */
    puts("ERROR!");
else
    puts("OK!");

但请记住,无论 len 的值如何,您机器中的 sizieof(buff) 都将是 8,您无法计算 malloced 块的长度,您需要存储它的长度以备后用。

如果需要,您可以创建一个结构来保存长度和数据。

if (len > sizeof(buff))

sizeof 产生一个 size_t 类型的值,它是无符号的。当您将它与负值 int 进行比较时,负值会提升为一个非常大的无符号值。 (无符号类型总是使用 modular arithmetic,并且它们在二进制运算中胜过有符号类型。)因此,-2 是 "greater than" 您可以从 sizeof.

得到的任何东西

Changing the value of len has no effect on the value of sizeof(buff), not even for a positive len.

sizeof(buff)是指针的大小,不是分配块的大小。您需要将其保存在您自己的变量中,因为 C 不会跟踪分配大小。

What's the difference between a char[] and char* from malloc?

char[]是一个数组,其大小取决于其中元素的数量。 char* 是一个指针。数组可以用在带有指针的上下文中,但这本身并不能使它成为指针。

sizeof( &* array )sizeof( & array[0] ) 将与 sizeof( ptr ) 具有相同的值。大小是变量的 属性,而不是内存块的大小。

1) Why is the above if statement printing ERROR? (Since -2 is not greater than 8 !!)

在if语句的条件表达式中

if (len > sizeof(buff))
    puts("ERROR!");

类型size_t(通常定义为unsigned long)对应于运算符sizeof的返回值类型比具有类型[的变量len的类型具有更高的等级int。所以为了得到通用类型 len 根据 通常算术转换 的规则转换为类型 size_t 并被视为大于 sizeof 返回值的无符号整数值(浅黄色)。

[注意:-2 的内部表示可以看起来(为了简单起见,我将只使用一个字节)像

11111110

8 看起来像

00001000

因此,如果将 -2 的内部表示视为某个无符号值,那么显然 -2 大于 8。 - 尾注]

来自 C 标准(6.3.1.8 常用算术转换)

1 Many operators that expect operands of arithmetic type cause conversions and yield result types in a similar way. The purpose is to determine a common real type for the operands and result. For the specified operands, each operand is converted, without change of type domain, to a type whose corresponding real type is the common real type. Unless explicitly stated otherwise, the common real type is also the corresponding real type of the result, whose type domain is the type domain of the operands if they are the same, and complex otherwise. This pattern is called the usual arithmetic conversions:

Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.

Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.

例如,如果您将 len 定义为 long long 类型,则条件可能等于 false,因为 long long 的等级可能大于等级size_t 的通常定义为类型 unsigned long

的 typedef

试试下面的代码片段

long long int len = -2;
char* buff = (char*) malloc(len+4);
if (len > sizeof(buff))
    puts("ERROR!");
else
    puts("OK!");

2) Why doesn't the following code print 8?

char array[10];
printf("%lu", sizeof(array));

运算符sizeof returns 以字节为单位用作运算符操作数的对象的大小。可变数组定义为 10 个 char 类型元素的数组。在任何实现中 sizeof( char ) 都等于 1。因此 10 * sizeof( char ) 将导致 10.

考虑到数组不是指针。