简体   繁体   English

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

[英]Pointer to int == Pointer to char (somewhat)?

In this code given below , i have declared a pointer to int and we all know that memcpy returns a void pointer to destination string , so if ptr is a pointer to int then why printf("%s",ptr);在下面给出的这段代码中,我声明了一个指向 int 的指针,我们都知道 memcpy 返回一个指向目标字符串的 void 指针,所以如果 ptr 是指向 int 的指针,那么为什么printf("%s",ptr); is totally valid , ptr is not a pointer to char after all.是完全有效的, 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;
}

First consider ptr = memcpy(a1,a2,strlen(a2)-1);首先考虑ptr = memcpy(a1,a2,strlen(a2)-1); . . memcpy is declared as void *memcpy(void * restrict, const void * restrict, size_t) , so it accepts the a1 and a2 passed to it because pointers to any unqualified object type may be converted to void * or to const void * . memcpy被声明为void *memcpy(void * restrict, const void * restrict, size_t) ,因此它接受传递给它的a1a2 ,因为指向任何非限定对象类型的指针都可以转换为void *const void * (Pointers to object types qualified with const may also converted to const void * .) This follows from the rules for function calls in C 2018 6.5.2.2 7 (arguments are converted to the parameter types as if by assignment) and 6.5.16 1 (one operand is a possibly-qualified void * and the left has all the qualifiers of the right) and 6.5.16 2 (the right operand is converted to the type of the left). (指向用const限定的对象类型的指针也可以转换为const void * 。)这遵循 C 2018 6.5.2.2 7 中的函数调用规则(参数转换为参数类型,就像通过赋值一样)和 6.5.16 1 (一个操作数是可能限定的void *并且左侧具有右侧的所有限定符)和 6.5.16 2 (右侧操作数转换为左侧的类型)。

Then memcpy returns a void * that is its first argument (after conversion to void * ), and we attempt to assign this to ptr .然后memcpy返回一个void *作为它的第一个参数(在转换为void *之后),我们尝试将其分配给ptr This satisfies the constraints of the assignment (one of the operands is a void * ), so it converts the pointer to the type of ptr , which is int * .这满足了赋值的约束(其中一个操作数是void * ),因此它将指针转换为ptr的类型,即int * This is governed by 6.3.2.3 7:这受 6.3.2.3 7 的约束:

A pointer to an object type may be converted to a pointer to a different object type.指向对象类型的指针可以转换为指向不同对象类型的指针。 If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined.如果结果指针未正确对齐引用的类型,则行为未定义。 Otherwise, when converted back again, the result shall compare equal to the original pointer…否则,当再次转换回来时,结果将等于原始指针......

Since a1 is a char array with no alignment requested, it could have any alignment.由于a1是一个没有要求对齐的char数组,它可以有任何对齐。 It might not be suitable for an int .它可能不适合int If so, then the C standard does not define the behavior of the program, per the above.如果是这样,那么 C 标准没有根据上述定义程序的行为。

If a1 happens to be suitably aligned for an int or the C implementation successfully converts it anyway, we go on to printf("%s \n",ptr);如果a1恰好与int对齐,或者 C 实现成功转换它,我们继续printf("%s \n",ptr); . .

printf is declared as int printf(const char * restrict, ...) . printf被声明为int printf(const char * restrict, ...) For arguments corresponding to ... , there is no parameter type to convert to.对于与...对应的参数,没有要转换的参数类型。 Instead, the default argument promotions are performed.而是执行默认参数提升 These affect integer and float arguments but not pointer arguments.这些影响整数和float参数,但不影响指针参数。 So ptr is passed to printf unchanged, as an int * .因此ptrint *的形式不变地传递给printf

For a %s conversion, the printf rules in 7.21.6.1 8 say “the argument shall be a pointer to the initial element of an array of character type.”对于%s转换,7.21.6.1 8 中的printf规则说“参数应该是指向字符类型数组的初始元素的指针。” While ptr is pointing to the same place in memory as the initial element, it is a pointer to an int , not a pointer to the initial element.虽然ptr指向与初始元素相同的内存位置,但它是指向int的指针,而不是指向初始元素的指针。 Therefore, it is the wrong type of argument.因此,这是错误的论证类型。

7.21.6.1 9 says “… If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.” 7.21.6.1 9 说“......如果任何参数不是相应转换规范的正确类型,则行为未定义。” Therefore, the C standard does not define the behavior of this program.因此,C 标准没有定义该程序的行为。

In many C implementations, pointers are simple addresses in memory, int * and char * have the same representation, and the compiler will tolerate passing an int * for a %s conversion.在许多 C 实现中,指针是内存中的简单地址, int *char *具有相同的表示形式,编译器将允许传递int *以进行%s转换。 In this case, printf receives the address it is expecting and will print the string in a1 .在这种情况下, printf接收到它所期望的地址,并将在a1中打印字符串。 That is why you observed the result you did.这就是为什么你观察到你所做的结果。 The C standard does not require this behavior. C 标准不需要这种行为。 Because printf is part of the standard C library, the C standard permits a compiler to treat it specially when it is called with external linkage.因为printf是标准 C 库的一部分,所以 C 标准允许编译器在使用外部链接调用它时对其进行特殊处理。 The compiler could, hypothetically, treat the argument as having the correct type (even though it does not) and change the printf call into a loop that used ptr as if it were a char * .假设编译器可以将参数视为具有正确的类型(即使它没有)并将printf调用更改为使用ptr的循环,就好像它是char *一样。 I am not aware of any compilers that would generate undesired code in this case, but the point is the C standard does not prohibit it.我不知道在这种情况下会生成不需要的代码的任何编译器,但关键是 C 标准并没有禁止它。

why printf("%s",ptr);为什么 printf("%s",ptr); is totally valid完全有效

It isn't - it may work as expected, but it isn't guaranteed to.它不是 - 它可能会按预期工作,但不能保证。 By passing an argument of the wrong type to printf , you've invoked undefined behavior, which simply means the compiler isn't required to handle the situation in any particular way.通过将错误类型的参数传递给printf ,您调用了未定义的行为,这仅仅意味着编译器不需要以任何特定方式处理这种情况。 You may get the expected output, you may get garbage output, you may get a runtime error, you may corrupt the state of your system, you may open a black hole to the other side of the universe.你可能会得到预期的输出,你可能会得到垃圾输出,你可能会得到一个运行时错误,你可能会破坏你的系统状态,你可能会打开一个通往宇宙另一端的黑洞。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM