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



请参阅以下代码片段:

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[]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 longsize_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。

考虑到数组不是指针。

相关内容

  • 没有找到相关文章

最新更新