在malloc中输入类型

时间:2016-02-11 16:56:29

标签: c pointers casting malloc

我知道这件事:Do I cast the result of malloc?

我读了它和其他问题,我仍然不满足于我的担忧。我知道类型转换会隐式发生,但无论我多少阅读这些参数,错误都是我无法理解的。

主要论点是intpointer可能有不同的大小。为了举例,让int*的大小为8,int的大小为4。

int *x = (int*) malloc(sizeof(int));

首先,malloc()分配的字节数为4,尽管变量x将存储大小为8字节的指针。

我明确地将malloc的返回值转换为(int *),顺便说一下,其大小为8.这里有什么丢失的位数?

4 个答案:

答案 0 :(得分:2)

如果您没有#include d stdlib.hmalloc的返回值很可能会在返回到调用代码之前被截断。从理论上讲,它是未定义的行为。如果malloc的返回值被截断,则类似于使用:

int a = 10;
int* ap = &a;
int temp = (int)ap;    // This is where you lose the pointer value due to truncation.
int* bp = (int*)temp;

答案 1 :(得分:2)

你的房子说50英尺宽。 你的房子地址是'40,Church st,Newtown'。 假设有一个像沃尔玛这样的大商店或你家附近的学校。那是450英尺宽。 但地址是50,Church St,Newtown'。

您是否需要使用不同尺寸的纸张来写入这些地址,因为其中一个比其他地址大?当然不是。 指针与地址同义。这是位置。存储在那里的(在你的情况下为4字节的int)不会改变地址长度。

所以最后,x的大小为8,并指向4字节大小。

答案 2 :(得分:1)

让我们看看可以发生什么。假设这段代码:

#include <stdio.h>
int main(int argc, char ** argv) {
  printf("sizeof(int) = %zu\nsizeof(int *) = %zu\n",
    sizeof(int), sizeof(int *));
  // output:
  // sizeof(int) = 4
  // sizeof(int *) = 8
  int * foo = (int *) malloc(sizeof(int));
  return 0;
}

在我的系统上使用clang ouch.c进行编译会产生:

ouch.c:5:23: warning: implicitly declaring library function 'malloc' with type 'void *(unsigned long)'
  int * foo = (int *) malloc(sizeof(int));
                      ^
ouch.c:5:23: note: include the header <stdlib.h> or explicitly provide a declaration for 'malloc'

在这里,clang很聪明地注意到我正在调用malloc,这是一个已知的库函数,并假设(正确的)函数签名void *(unsigned long)。一切都很好。但并不是每个编译器都那么聪明,而且我也可以欺骗它:

#include <stdio.h>
int main(int argc, char ** argv) {
  printf("sizeof(int) = %zu\nsizeof(int *) = %zu\n",
    sizeof(int), sizeof(int *));
  int * foo = (int *) wrapper();
  return 0;
}

在一个单独的文件中,我将链接到上面的主文件:

#include <stdlib.h>
void * wrapper(void) {
  return malloc(sizeof(int));
}

正在运行clang wrapper.c ouch2.c给我:

ouch2.c:5:23: warning: implicit declaration of function 'wrapper' is invalid in C99 [-Wimplicit-function-declaration]
  int * foo = (int *) wrapper();
                      ^
ouch2.c:5:15: warning: cast to 'int *' from smaller integer type 'int' [-Wint-to-pointer-cast]
  int * foo = (int *) wrapper();
              ^
2 warnings generated.

这是非常好的,因为如果这些警告被读取,然后它很容易理解问题的根源并修复它们。但如果我忽略它们并保持代码不变,则会发生以下情况:

编译ouch2.c时,clang没有看到wrapper的任何声明。因为我从循环it has no choice but to assume that somewhere this is declared as

中删除了它的智能库函数检测
int wrapper();

这是一个函数返回int并获取任意数量的参数。我们看到了这样的证据,因为clang(作为一个智能编译器)警告我关于(返回)intint *的演员及其第二次警告。

int投射到int *并不是什么坏事。什么 不好假设我们首先得到int。假设malloc函数中对wrapper的调用返回了此值:

0xAABBCCDD11223344

然后会发生什么取决于调用约定。我们假设它将此值作为返回值放入某个64位寄存器。

main中的调用代码需要int,因此它只从寄存器中读取32位(可能是下半部分)并使用它。所以在main中,我从wrapper得到了这个:

0x11223344

然后将其转换为(64位)int *,可能导致:

0x0000000011223344

然后用作内存地址。访问这个地址可能(如果你很幸运)会导致分段错误或(如果你不是那么幸运)更改一些随机数据(如果它发生在堆栈上,这会变得特别有趣,例如更改返回地址)

所以,最后但并非最不重要的,如果我离开演员阵容:

#include <stdio.h>
int main(int argc, char ** argv) {
  printf("sizeof(int) = %zu\nsizeof(int *) = %zu\n",
    sizeof(int), sizeof(int *));
  int * foo = wrapper();
  return 0;
}

clang wrapper.c ouch3.c编译,我得到:

ouch3.c:5:15: warning: implicit declaration of function 'wrapper' is invalid in C99 [-Wimplicit-function-declaration]
  int * foo = wrapper();
              ^
ouch3.c:5:9: warning: incompatible integer to pointer conversion initializing 'int *' with an expression of type 'int' [-Wint-conversion]
  int * foo = wrapper();
        ^     ~~~~~~~~~
2 warnings generated.

也是一个警告,但是一个不同的警告。这种(某种)警告很可能由编译器产生。

长话短说:clang对潜在错误做了很好的警告并且没有强制转换返回值,因为如果忘记包含stdlib.h,即使没有使用clang进行编译,也可以确定会收到警告:)

答案 3 :(得分:0)

请注意,在“int * x”中,x变量一旦定义就已分配。它是一个指针,即它包含堆内的地址。然而,在作业之前它的价值毫无意义;就像任何其他变量一样。 malloc(n)确保返回值的地址中的n个字节在内存中分配。换句话说,x的大小为8,但x [0]的大小为4,malloc(4)分配了足够的内存来存储x [0]。 看到差异的一个好方法是比较&amp; x和&amp; x [0]。后者将等于x。