无法解释此 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
.
我使用以下代码打印了 len
和 sizeof(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[]
和 malloc
的 char*
有什么区别?我知道前者是在栈上分配的,后者是在堆上动态分配的,但不管怎么说都是系统内存的指针地址。我不明白 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
警告,它会告诉你signed
unsigned
比较。
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
,您无法计算 malloc
ed 块的长度,您需要存储它的长度以备后用。
如果需要,您可以创建一个结构来保存长度和数据。
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.
考虑到数组不是指针。
查看以下代码片段:
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
.
我使用以下代码打印了 len
和 sizeof(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[]
和 malloc
的 char*
有什么区别?我知道前者是在栈上分配的,后者是在堆上动态分配的,但不管怎么说都是系统内存的指针地址。我不明白 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
警告,它会告诉你signed
unsigned
比较。
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
,您无法计算 malloc
ed 块的长度,您需要存储它的长度以备后用。
如果需要,您可以创建一个结构来保存长度和数据。
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[]
andchar*
frommalloc
?
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
试试下面的代码片段
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.
考虑到数组不是指针。