请参阅以下代码片段:
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
!似乎不一致!
if (len > sizeof(buff))
sizeof
产生一个 size_t
类型的值,该值是无符号的。当您将其与负int
进行比较时,负值将提升为非常大的无符号值。(无符号类型始终使用模算术,它们在二进制运算中胜过有符号类型。因此,-2
"大于"您可以从sizeof
获得的任何东西。
更改 len 的值对 sizeof(buff) 的值没有影响,即使对于正 len 也是如此。
sizeof(buff)
是指针的大小,而不是分配块的大小。您需要将其保存在自己的变量中,因为 C 不跟踪分配大小。
char[]
和malloc
char*
有什么区别?
char[]
是一个数组,其大小取决于其中元素的数量。char*
是一个指针。数组可以在接受指针的上下文中使用,但这本身并不能使它成为指针。
sizeof( &* array )
或sizeof( & array[0] )
都将具有与sizeof( ptr )
相同的值。大小是变量的属性,而不是内存块的属性。
你的代码有什么问题?
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
环绕
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块的长度,您需要存储其长度以供后续使用。
如果需要,可以创建一个结构来保存长度和数据。
1)为什么上述if语句打印错误?(因为 -2 不是 大于 8 !!
在 if 语句的条件表达式中
if (len > sizeof(buff))
puts("ERROR!");
类型size_t
(通常定义为 unsigned long
)对应于运算符sizeof
的返回值的类型,其秩高于类型为 int
的变量 Len 的类型。因此,为了获得公共类型,len 根据通常算术转换的规则转换为类型 size_t
,并被视为大于 sizeof( buff 返回的值的无符号整数值)。
[注意:-2
的内部表示可以看起来像(为简单起见,我将只使用一个字节)像
11111110
虽然8
它看起来像
00001000
因此,如果将-2
的内部表示视为某个无符号值,那么很明显-2
大于8
。
来自 C 标准(6.3.1.8 常用算术转换)
1 许多期望算术类型操作数的运算符导致 以类似的方式进行转化和收益结果类型。目的是 确定操作数和结果的通用实数类型。对于 指定的操作数,转换每个操作数,不更改类型 域,其对应的实数类型为公共实数的类型 类型。除非另有明确说明,否则常见的实数类型也是 结果的相应实际类型,其类型域为 操作数的类型域(如果它们相同且复杂) 否则。这种模式称为通常的算术转换:
和
否则,如果两个操作数都有有符号整数类型,或者两者都有 无符号整数类型,类型为较小整数的操作数 转换等级转换为具有更大操作数的类型 排。
否则,如果具有无符号整数类型的操作数具有秩 大于或等于其他操作数类型的秩,则 具有有符号整数类型的操作数将转换为 具有无符号整数类型的操作数。
例如,如果您将len
定义为具有类型 long long
,那么条件可能等于 false,因为可能会出现长长长的秩大于通常定义为类型 unsigned long
的 size_t
秩
尝试以下代码片段
long long int len = -2;
char* buff = (char*) malloc(len+4);
if (len > sizeof(buff))
puts("ERROR!");
else
puts("OK!");
2)为什么下面的代码不打印8?
char array[10];
printf("%lu", sizeof(array));
运算符 sizeof
返回用作运算符操作数的对象的大小(以字节为单位)。变量数组定义为由 char 类型的 10 个元素组成的数组。在任何实现中,sizeof( char ) 等于 1。因此 10 * sizeof( char ) 将产生 10。
考虑到数组不是指针。