将一个字符的空间分配给一个整型指针

4

我正在学习C语言,但以下代码片段在GCC编译器中并未出现任何警告或错误。我给指向int类型的指针分配了一个字符的空间,这是GCC做的一些更改(例如默默地优化为int类型分配的空间)吗?

#include <stdlib.h>
#include <stdio.h>

typedef int *int_ptr;

int main()
{
  int_ptr ip;
  ip = calloc(1, sizeof(char));
  *ip = 1000;
  printf("%d", *ip);
  free(ip);
  return 0;
}

更新

阅读下面的回答后,如果我采用相反的方式进行操作,例如将int的空间分配给char指针,那么是否仍然不安全和有风险?我的困惑源于Rosetta Code中的以下答案,在函数StringArray StringArray_new(size_t size)中,编码者似乎确实在做这个操作:this->elements = calloc(size, sizeof(int));其中this->elements是一个char ** elements


3
你可能会读到关于"未定义行为"的内容。你的代码写入了不属于它的内存,这是非法的。任何事情都有可能发生,甚至可能看起来正常工作。 - Gerhardh
那么 ip 是为 int 还是 char 分配了空间? - Student
1
@学生 你为它分配了1个字节的存储空间,所以你只能写入1个字节。如果你像你的代码一样写入更多的内容,那么你就会破坏内存并可能遇到意外结果、分段错误等问题。这是一个严重的错误。在像C这样的语言中,避免这样的错误取决于你自己。代码将比解释性语言运行得快得多,但它不会为你检测这样的错误。 - Tom Karzes
2
写入32位整数会写入4个字节,无论它们的值如何,这不是编译器的问题,而是处理器的行为。 - Weather Vane
1
顺便提一下,存储16位数字1的两种常见方式是00000000000000010000000100000000。请阅读有关字节序的内容。 - klutt
显示剩余12条评论
4个回答

4
calloc的结果是void*类型,隐式转换成int*类型。C编程语言和GCC相信程序员能写出明智的强制转换并因此不会产生任何警告。尽管会在运行时产生无效内存写入,但您的代码在技术上是有效的C。所以,不,GCC不会隐式地为整数分配空间。
如果您想在运行(或编译)之前看到这种警告,您可能想使用Clang Static Analyzer等工具。
如果您想在运行时看到这种错误,请使用Valgrind运行程序。
更新
分配1个int的空间(即4个字节,通常)然后将其解释为char(1 char为1字节)不会导致任何内存错误,因为int所需的空间大于char所需的空间。实际上,您可以将结果用作4个char的数组。sizeof运算符以字节数的形式返回该类型的大小。calloc函数然后分配该数量的字节,它不知道将存储在分配的段中的类型。
虽然这不会产生任何错误,但确实可以被视为“危险且不安全”的编程实践。对于希望重用同一内存段来存储不同类型值的高级应用程序,存在例外情况。
您链接到的Rosetta Code上的代码包含了该行的一个错误。它应该为char*而不是int分配内存。这些通常不相等。在我的机器上,int的大小为4个字节,而char*的大小为8个字节。

3

C语言的类型安全性很差,而且malloc函数没有类型检查。它分配的字节数完全取决于所提供的参数。编译器不会负责警告这个问题,而是由程序员来确保参数正确。

它“似乎正常工作”的原因是因为出现了未定义行为*ip = 1000;同样可能会导致程序崩溃。有关未定义行为的更多信息,请参见什么是未定义行为以及它是如何工作的?

此外,您永远不应该在typedef中隐藏指针。这是非常糟糕的实践,只会让程序员和阅读代码的人感到困惑。


1
编译器只关心您向传递了正确数量和类型的参数,它不会检查这些参数是否有意义,因为这是一个运行时问题。是的,当两个参数都是常量表达式并且像这种情况下的操作时,您可能可以向编译器添加一些特殊情况逻辑,但是如果两个参数都是运行时变量,例如,它将如何处理?这是C语言假定您足够聪明以知道自己在做什么的情况之一。

0

编译器只检查语法,不检查语义。

你的代码语法没问题,但语义有误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接