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

时间:2015-01-11 13:58:22

标签: c arrays pointers malloc

请参阅以下代码段:

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[]的{​​{1}}和char*之间有什么区别?我知道第一个是在堆栈上分配的,后者是在堆上动态分配的,但无论如何它们都是系统内存的指针地址。我不理解malloc相对于来自sizeof的{​​{1}}和char[]的不同行为!这似乎不一致!

3 个答案:

答案 0 :(得分:4)

您的代码有什么问题?

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!");

但请记住,无论sizieof(buff)的值如何,您机器中的8都为len,您无法计算malloc ed块的长度,你需要存储它的长度以供后续使用。

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

答案 1 :(得分:4)

if (len > sizeof(buff))

sizeof生成类型为size_t的值,该值为无符号。将其与负int进行比较时,负值将提升为非常大的无符号值。 (无符号类型始终使用modular arithmetic,并且它们在二进制运算中胜过签名类型。)因此,-2“大于”sizeof可以获得的任何内容。

  

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

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

  

来自char[]的{​​{1}}和char*之间有什么区别?

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

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

答案 2 :(得分:2)

  

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

在if语句的条件表达式

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

类型size_t(通常定义为unsigned long)对应于运算符sizeof的返回值的类型,其排名高于类型为{{1的变量len的类型}}。因此,要根据通常的算术转换的规则将公共类型len转换为类型int,并将其视为无符号整数值,该值大于sizeof(buff)返回的值

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

-2

11111110 看起来像是

8

因此,如果将00001000 的内部表示视为某些无符号值,则-2显然大于-2。 - 结束注释]

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

  

1许多期望算术类操作数的运算符会导致   以类似的方式转换和生成结果类型。目的是为了   确定操作数和结果的通用实数类型。为了   指定的操作数,每个操作数都被转换,不改变类型   域,对应的实际类型是普通实数的类型   类型。除非另有明确说明,否则常见的实际类型也是如此   结果的相应实际类型,其类型域为   操作数的类型域,如果它们是相同的,并且是复杂的   除此以外。这种模式称为通常的算术转换:

  

否则,如果两个操作数都有有符号整数类型或两者都有   无符号整数类型,操作数类型为较小的整数   转换等级转换为具有更大的操作数的类型   秩。

     

否则,如果具有无符号整数类型的操作数具有等级   那么,大于或等于另一个操作数的类型的等级   带有符号整数类型的操作数转换为   具有无符号整数类型的操作数。

如果您将8定义为具有类型len,那么条件将等于false是可能的,因为可能发生long long的等级大于{的等级{1}}通常被定义为类型long long

的typedef

尝试以下代码段

size_t
  

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

unsigned long

运算符long long int len = -2; char* buff = (char*) malloc(len+4); if (len > sizeof(buff)) puts("ERROR!"); else puts("OK!"); 以字节为单位返回用作运算符操作数的对象的大小。变量数组定义为10个char类型元素的数组。在任何实现中,sizeof(char)等于1.因此10 * sizeof(char)将导致10。

考虑到数组不是指针。