C函数指针的行为,数组/数组指针行为 [英] C function pointer behavior, array/array pointer behavior

查看:151
本文介绍了C函数指针的行为,数组/数组指针行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下code:

 的#include<&stdio.h中GT;INT ret_five(){
  返回5;
}诠释主(){
  INT X [5] = {1,2,3,4,5};  INT(* p)的();
  P =&放大器; ret_five;
  的printf(%d个\\ N,P()); // 1
  P = ret_five;
  的printf(%d个\\ N,P()); // 2  的printf(%d个\\ n,sizeof的ret_five); // 3
  的printf(%d个\\ n,sizeof的&安培; ret_five); // 4  的printf(%d个\\ N(* P)()); // 5
  的printf(%d个\\ N(**** P)()); // 6  的printf(%P \\ N,P); // // 7编辑:替换%P%d个
  的printf(%P \\ N,* P); // 8 //这里相同和(8),(10)
  的printf(%P \\ N,** P); // 9
  的printf(%P \\ N,******* P); // 10  的printf(%P \\ N,X); // 11
  的printf(%P \\ N,&安培; X); // 12
  返回0;
}

我的问题是:


  1. 线(1)和(2)中打印的相同的结果。做 ret_five &放大器; ret_five 有相同的数据类型?好像没有,因为线(3)和(4)打印不同的结果。


  2. 从一个语法点,在我看来,这条线(5)应调用该函数的正确方法是 P 点到的,但当然线(1)和(2)打印5就好了。是否有技术原因,或者说是一个设计决策作出,因为在调用(1)和(2)看起来更干净?还是别的什么?


  3. 线(5)非常有意义,我(因为 P 是一个函数指针,它的解除引用值的功能,我们调用函数,它返回5,我们打印5)。我很惊讶地发现,(6)印刷5的!这是为什么?


  4. 同样,线(7) - (10)所有打印相同的值,即&放大器; ret_five 。为什么(10)工作的?


  5. 线(11)和(12)中打印的相同的值,即其中的第一元素x 住在存储器中的地址。线(12)是有道理的,但我不明白到底是什么在网上(11)在技术上发生。是否 X 自动获得铸造或PTED为为int * 在这种情况下跨$ P $?


  6. 要获得在内存中的位置,其中 X 存储,我通常做&放大器; X [0] ,但它似乎像&放大器; X 工作也很不错,因为 X 是一个数组,而不是一个指针,好像实际上&放大器; X 会收到此内存地址的更正规途径。是否有一个理由,preFER一个到另一个?


  7. 在一般情况下,在上述情况出现的最佳​​实践?例如,如果 P = ret_five; P =&放大器; ret_five 真正做同样的事情,有没有原因preFER一个到另一个?


  8. 和,如果有问题7这两个任务真正做同样的事情,为什么,因为否则如此严格的语言,是这样的松弛内置的?



解决方案

函数标志是具有函数型的前pression。除非它是
sizeof操作符或单目&运算符,函数与标志的操作
类型»函数返回类型«被转换成具有类型»指向一个前pression
函数返回类型«。

ret_five和&安培; ret_five评价都到同一个函数指针。 sizeof的ret_five是违反约束和你的编译器应该输出的诊断。所以,ret_five是一个功能指示器,是在所有的(但两(见上文))的情况下转换为对所述函数,* ret_five又是一个功能指示符,被再次转换为指针所述功能如果使用它的指针在除上述两种任何上下文,所以** ret_five又是一个功能指示符,等等。打印这样的终场%d为不确定的行为,因为%d为整数为

P = ret_five是现代C.正确使用和放大器; ret_five反而是老式的,20世纪80年代ç


除非该值是sizeof运算符或单目&运算符的操作数,或者是
字符串用于初始化数组,具有输入型»阵列«是一个前pression
转换为具有类型»指针的前pression键入«指向的初始元素
数组对象,而不是一个左值。

x和&放大器; x具有相同的数值(它们是指向X的第一元素),但不同的类型。点¯x计算结果为指针为int,但与放大器;,X计算结果为指针五个整数数组

Consider the following code:

#include <stdio.h>

int ret_five() {
  return 5;
}

int main() {
  int x[5] = {1,2,3,4,5};

  int (*p)();
  p = &ret_five;
  printf("%d\n", p());              // 1
  p = ret_five;
  printf("%d\n", p());              // 2

  printf("%d\n", sizeof ret_five);  // 3
  printf("%d\n", sizeof &ret_five); // 4

  printf("%d\n", (*p)());           // 5
  printf("%d\n", (****p)());        // 6

  printf("%p\n", p);                // 7   // edited: replaced %d with %p
  printf("%p\n", *p);               // 8   //   same here and in (8), (10)
  printf("%p\n", **p);              // 9
  printf("%p\n", *******p);         // 10

  printf("%p\n", x);                // 11
  printf("%p\n", &x);               // 12
  return 0;
}

My questions are:

  1. Lines (1) and (2) print the same result. Do ret_five and &ret_five have the same data type? It seems like no, because lines (3) and (4) print different results.

  2. From a syntactical point of view, it seems to me that line (5) should be the right way to call the function that p points to, but of course lines (1) and (2) print 5 just fine. Is there a technical reason for this, or was it a design decision made because the calls in (1) and (2) look cleaner? Or something else?

  3. Line (5) makes perfect sense to me (because p is a function pointer, its dereferenced value is the function, we call the function, it returns 5, we print 5). I was very surprised to find that (6) prints 5 as well! Why is this?

  4. Similarly, lines (7)--(10) all print the same value, namely &ret_five. Why does (10) work?

  5. Lines (11) and (12) print the same value, namely the address where the first element of x lives in memory. Line (12) makes sense, but I don't quite understand exactly what is technically happening in line (11). Does x automatically get cast or interpreted as an int* in this context?

  6. To get the location in memory where x is stored, I typically do &x[0], but it seems like &x works just fine as well, and because x is an array and not a pointer, it seems like in fact &x may be the more canonical way of getting this memory address. Is there a reason to prefer one to the other?

  7. In general, are there best-practices in the above situations? For example, if p = ret_five; and p = &ret_five really do the exact same thing, is there a reason to prefer one to the other?

  8. And, if the two assignments in question 7 really do the exact same thing, why, in a language that is otherwise so rigid, was this laxity built-in?

解决方案

A function designator is an expression that has function type. Except when it is the operand of the sizeof operator or the unary & operator, a function designator with type »function returning type« is converted to an expression that has type »pointer to function returning type«.

ret_five and &ret_five both evaluate to the same function pointers. sizeof ret_five is a constraint violation and your compiler should output a diagnostic. So, ret_five is a function designator that is in all (but two (see above)) situations converted to a pointer to said function, *ret_five is again a function designator, which is AGAIN converted to a pointer to said function if you use it in any context except the two above, so **ret_five is again a function designator, and so on. Printing such a pointer with %d is undefined behavior since %d is for ints.

p = ret_five is correct in modern C. Using &ret_five instead is old fashioned, 1980s C.

Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type »array of type« is converted to an expression with type »pointer to type« that points to the initial element of the array object and is not an lvalue.

x and &x have the same numerical value (they are pointers to x's first element) but different types. x evaluates to a pointer to int, but &x evaluates to a pointer to an array of five ints.

这篇关于C函数指针的行为,数组/数组指针行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆