指向 int == 指向 char 的指针(有点)?

王子

在下面给出的这段代码中,我声明了一个指向 int 的指针,我们都知道 memcpy 返回一个指向目标字符串的空指针,所以如果 ptr 是指向 int 的指针,那么为什么printf("%s",ptr); 是完全有效的,毕竟 ptr 不是指向 char 的指针。

#include <stdio.h>
#include <string.h>
//Compiler version gcc  6.3.0

int main()
{
  char a1[20] ={0} , a2[20] ={0};
  int *ptr;
  fgets(a1,20,stdin);
  fgets(a2,20,stdin);
  ptr = memcpy(a1,a2,strlen(a2)-1);
  printf("%s \n",ptr);
  if(ptr)
  printf("%s",a1);
  return 0;
}
埃里克·波斯皮希尔

首先考虑ptr = memcpy(a1,a2,strlen(a2)-1);memcpy被声明为void *memcpy(void * restrict, const void * restrict, size_t),因此它接受a1a2传递给它,因为指向任何非限定对象类型的指针都可以转换为void *const void *(指向用 限定的对象类型的指针const也可以转换为const void *。)这遵循 C 2018 6.5.2.2 7 中的函数调用规则(参数被转换为参数类型,就像通过赋值一样)和 6.5.16 1(一个操作数是a 可能限定void *并且左侧具有右侧的所有限定符)和 6.5.16 2(右侧操作数转换为左侧的类型)。

然后memcpy返回 a void *,它是它的第一个参数(转换为 之后void *,我们尝试将其分配给ptr。这满足赋值的约束(其中一个操作数是 a void *),因此它将指针转换为 的类型ptr,即int *。这受 6.3.2.3 7 约束:

指向对象类型的指针可以转换为指向不同对象类型的指针。如果结果指针未针对引用类型正确对齐,则行为未定义。否则,当再次转换回来时,结果将与原始指针相等......

由于a1是一个char没有要求对齐数组,它可以有任何对齐。它可能不适合int. 如果是这样,则 C 标准没有定义程序的行为,如上所述。

如果a1碰巧与 an 适当对齐,int或者 C 实现无论如何都成功转换了它,我们继续printf("%s \n",ptr);

printf被声明为int printf(const char * restrict, ...). 对于对应于 的参数...,没有要转换为的参数类型。而是执行默认参数提升这些影响整数和float参数,但不影响指针参数。Soptr传递给printf不变,作为int *.

对于%s转换,printf7.21.6.1 8 中规则说“参数应该是指向字符类型数组的初始元素的指针。” 虽然ptr指向内存中与初始元素相同的位置,但它是指向 anint的指针,而不是指向初始元素的指针。因此,这是错误的论证类型。

7.21.6.1 9 说“……如果任何参数不是相应转换规范的正确类型,则行为未定义。” 因此,C 标准没有定义该程序的行为。

在许多 C 实现中,指针是内存中的简单地址,int *并且char *具有相同的表示形式,并且编译器将容忍传递一个int *用于%s转换。在这种情况下,printf接收它期望的地址并将在a1. 这就是为什么你观察你所做的结果。C 标准不需要这种行为。因为它printf是标准 C 库的一部分,所以 C 标准允许编译器在使用外部链接调用时对其进行特殊处理。假设编译器可以将参数视为具有正确的类型(即使它没有),并将printf调用更改为循环使用ptr,就好像它是一个char *. 我不知道在这种情况下有任何编译器会生成不需要的代码,但关键是 C 标准并没有禁止它。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章