C语言 在马洛克进行类型转换



我知道这一点:我是否投射了malloc的结果?

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

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

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

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

我明确地将 malloc 回归 (int *) ,顺便说一下,它的尺寸为 8。怎么会有位丢失?

如果你没有#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;

你的房子有50英尺宽。您的住址是"40, Church st, Newtown"。假设有一家像沃尔玛这样的大商店或你家旁边的学校。那是450英尺宽。但地址是"50,教堂街,纽敦"。

您是否需要不同尺寸的纸张来写入这些地址,因为一个地址比另一个大?当然不是。指针是地址的同义词。这是位置。存储在那里的内容(在您的情况下为 4 个字节(不会更改地址长度。

因此,在最后,x 的大小为 8,并将指向 4 字节大小。

让我们看看会发生什么。假设以下代码:

#include <stdio.h>
int main(int argc, char ** argv) {
  printf("sizeof(int) = %zunsizeof(int *) = %zun",
    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) = %zunsizeof(int *) = %zun",
    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 的声明。由于我从循环中删除了它的智能库函数检测,它别无选择,只能假设在某处将其声明为

int wrapper();

这是一个返回int并接受任意数量的参数的函数。我们看到了证据,因为 clang(作为一个智能编译器(警告我关于从(返回的(intint *的第二个警告的转换。

这种int投射到int *并不是这里的坏事。不好的是假设我们首先得到了一个int。假设在 wrapper 函数中调用 malloc 返回了以下值:

0xAABBCCDD11223344

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

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

0x11223344

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

0x0000000011223344

然后用作内存地址。访问此地址可能会(如果您幸运的话(导致分段错误或(如果您不那么幸运(更改一些随机数据(如果它发生在堆栈上,例如更改返回地址,这尤其有趣(。

所以,最后但并非最不重要的一点是,如果我把演员阵容排除在外:

#include <stdio.h>
int main(int argc, char ** argv) {
  printf("sizeof(int) = %zunsizeof(int *) = %zun",
    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 编译,也可以肯定会收到警告:)

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

相关内容

  • 没有找到相关文章

最新更新