关于分配函数返回指针到数组的警告 [英] Warning on assigning a function-returning-a-pointer-to-arrays

查看:99
本文介绍了关于分配函数返回指针到数组的警告的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您好。我或多或少是C新手。我以为我的指针一直处于控制之中

我开始玩弄这个:


=============== =================================== =============== ===============

/ *一个向调用函数返回数组指针的函数。 * /


#include< stdio.h>


int * pfunc(void);


int main(无效)

{

int(* pd)[5];


pd = pfunc( );


/ *应该返回20和9 * /

printf(" \ nDigits是:%d和%d,*(* (pd + 0)+ 3),*(*(pd + 1)+ 2));


返回0;

}


int * pfunc(void)

{

static int arr [2] [5] = {{5,10,15,20 ,25},{3,6,9,12,15}};


返回(* arr);

}


============================================ ====== ==============================

编译并正常工作,但编译器我试过它警告我

非法转换指针类型或可疑指针转换

关于:


pd = pfunc();


我''我很难过。我认为我的语法是正确的,并且

文献或该组的常见问题解答中没有任何内容可以告诉我;然而,如果我将

声明和初始化结合到:


int(* pd)[5] = pfunc();


.. 。警告消失了。这是怎么回事?


当我实现我正在努力实现的目标时,我没有

选项结合线条,这个警告有多严重?


非常感谢任何解释。

-


IM(绝对)!Knuth

Hi. I''m more-or-less a C newbie. I thought I had pointers under control until
I started goofing around with this:

================================================== ==============================
/* A function that returns a pointer-of-arrays to the calling function. */

#include <stdio.h>

int *pfunc(void);

int main(void)
{
int (*pd)[5];

pd = pfunc();

/* Should return 20 and 9 */
printf("\nDigits are: %d and %d", *(*(pd + 0) + 3), *(*(pd + 1) + 2) );

return 0;
}

int *pfunc(void)
{
static int arr[2][5] = {{5, 10, 15, 20, 25}, {3, 6, 9, 12, 15}};

return(*arr);
}

================================================== ==============================
It compiles and works correctly, but the compilers I''ve tried it on warn me of
"illegal conversion of pointer type" or "suspicious pointer conversion"
regarding:

pd = pfunc();

I''m stumped. I think my syntax is correct, and there''s nothing in the
literature or this group''s FAQ that tells me otherwise; yet, if I combine the
declaration and initialisation to:

int (*pd)[5] = pfunc();

.. . . the warnings go away. What''s up with that?

When I implement what I''m really working towards with this, I won''t have the
option of combining the lines, so how serious is this warning?

Any elucidation is greatly appreciated.
--

I.M. (definitely) !Knuth

推荐答案

IM !Knuth写道:
I.M. !Knuth wrote:
嗨。我或多或少是C新手。我以为我的指针一直处于控制状态,直到我开始玩弄这个:

======================= =========================== ======================= =======
/ *一个向调用函数返回数组指针的函数。 * /

#include< stdio.h>

int * pfunc(void);

int main(void)
{
int(* pd)[5];

pd = pfunc();

/ *应返回20和9 * /
printf (\ nDigits是:%d和%d,*(*(pd + 0)+ 3),*(*(pd + 1)+ 2));

返回0 ;
}
int * pfunc(void)
{
static int arr [2] [5] = {{5,10,15,20,25 },{3,6,9,12,15}};

返回(* arr);
}

======== ========================================== ======== ======================
它编译并正常工作,但是我试过的编译器警告我
;非法转换指针类型或可疑指针转换
关于:

pd = pfunc();

我很难过。我认为我的语法是正确的,并且
文献中没有任何内容或该组的常见问题解答告诉我其他内容;但是,如果我将
声明和初始化结合到:
Hi. I''m more-or-less a C newbie. I thought I had pointers under control until
I started goofing around with this:

================================================== ==============================
/* A function that returns a pointer-of-arrays to the calling function. */

#include <stdio.h>

int *pfunc(void);

int main(void)
{
int (*pd)[5];

pd = pfunc();

/* Should return 20 and 9 */
printf("\nDigits are: %d and %d", *(*(pd + 0) + 3), *(*(pd + 1) + 2) );

return 0;
}

int *pfunc(void)
{
static int arr[2][5] = {{5, 10, 15, 20, 25}, {3, 6, 9, 12, 15}};

return(*arr);
}

================================================== ==============================
It compiles and works correctly, but the compilers I''ve tried it on warn me of
"illegal conversion of pointer type" or "suspicious pointer conversion"
regarding:

pd = pfunc();

I''m stumped. I think my syntax is correct, and there''s nothing in the
literature or this group''s FAQ that tells me otherwise; yet, if I combine the
declaration and initialisation to:



它们是不同的类型。我的编译器提供了一个更有帮助的警告

说明了一切:


警告:赋值类型不匹配:

指向数组的指针[ 5of int="指向int的指针


-

Ian Collins。


They are different types. My compiler gives a more helpful warning
which says it all:

warning: assignment type mismatch:
pointer to array[5] of int "=" pointer to int

--
Ian Collins.


Ian Collins写道:
Ian Collins wrote:
它们是不同的类型。我的编译器提供了一个更有用的警告
,它说明了一切:

警告:赋值类型不匹配:
指向int=的数组[5]的指针指向int的指针
They are different types. My compiler gives a more helpful warning
which says it all:

warning: assignment type mismatch:
pointer to array[5] of int "=" pointer to int



这是有道理的。你碰巧知道我可以明确告诉编译器的方式吗?


pd [5] = pfunc();


.. 。还是一些这样的?如果我输入以上内容(我已经尝试了各种各样的

多彩组合,包括*)我得到:只有左值可以采取

赋值错误。


感谢您的关注。

-


IM(绝对)!Knuth



That makes sense. Do you happen to know of a way I can explicitly tell
the compiler:

pd[5] = pfunc();

.. . . or some such? If I enter the above (and I''ve tried all sorts of
colourful combinations, *s included) I get: "only lvalues may take
assignment" errors.

Thanks for you attention.
--

I.M. (definitely) !Knuth


在文章< MP ************************ @ news.telus.net>

IM!Knuth< no ******* @ yoyodyne.com>写道:
In article <MP************************@news.telus.net>
I.M. !Knuth <no*******@yoyodyne.com> wrote:
int * pfunc(void);


这将pfunc声明为不带参数的函数并返回

" int *"或指向int的指针。类型为指向int的指针的值可以

(但不一定)依次指向一个或多个ints
中的第一个,或者甚至指向这样一个序列的中间:


int * p1;

int x,y [4];


p1 = NULL; / * p1不指向任何ints * /

p1 =& x; / * p1指向单个int * /

p1 =& y [0]; / * p1指向4个整数中的第一个* /

p1 =& y [1]; / * p1指向4个整数中的第二个,所以p1 [-1]是y [0] * /


假设pfunc()将返回指向单个int的指针,或者至>
序列中的第一个ints。

int main(void)
{
int(* pd)[5 ]。


(顺便说一下main()的定义很好。:-))


" pd"具有类型指向int的数组5的指针。与上面的p1一样,它可以按顺序指向一个或多个数组5/bb的第一个中的
(不一定是确实)。

pd = pfunc();


类型不匹配:pfunc()返回指向int的指针,或者在int序列中返回一些int

。 " PD"需要指向一个数组5

of int,或者是第一个数组5 of int的序列。

/ *应该返回20并且9 * /
printf(\ nDigits是:%d和%d,*(*(pd + 0)+ 3),*(*(pd + 1)+ 2));


这可以更清楚地写成:


printf(" \ nDigits is:%d and%d",pd [ 0] [3],pd [1] [2]);

返回0;


为了严格的可移植性,请确保任何输出都是换行终止的

(例如,替换上面的printf格式\ n ..."使用... \ n,或者

" \ n ... \ n"如果您因某种原因喜欢额外的空白行。)

}

int * pfunc(void)
{
static int arr [2] [5] = {{5,10,15,20,25},{ 3,6,9,12,15}};


" arr"具有类型为int的数组5的数组2。也就是说,它是2个事物的数组

,其中每个事物都是是一个数组5的int。

arr [0]是第一个,arr [1]是第二个。

return(* arr) ;
}


除此之外:这里的括号是不必要的,尽管是无害的。 return的

语法返回值的语句是:


返回表达式;


当然表达式可以括在括号中。在任何情况下,

效果都是返回一个值。


* arr是写arr [0]的一种方法。这命名整个数组5

of int包含序列{5,10,15,20,25}。每当你在一个需要值的地方命名一个数组对象时,C编译器

将作为一个值产生该第一个元素的地址。 />
数组。因此:


返回arr [0];


"表示同样的事情:


return& arr [0] [0];


因此pfunc()返回指向&的指针; INT"持有值5

(即arr [0] [0]),这当然是序列中五个ints

中的第一个。


因为C'的数组总是一系列相同类型的

元素,在[%]之间没有间隙,所以这个序列为5。 int" s是

后面跟着构成

对象arr [1]的5int序列。也就是说,如果你能以某种方式平坦化数组,

连续得到2 * 5 = 10int,按住序列{5,10,

15,20,25,3 ,6,9,12,15}。

-----

%或者更确切地说,如果有差距,它们必须是隐形的

,只要你坚持使用定义的行为代码。

-----


(C标准不保证访问这个

flattened方式的数组将始终有效。可能有一些罕见的

情况,其中一个聪明的C编译器跟踪数组边界

信息,以便它知道,例如,arr [0] [i]永远不会有大于4的i
a值,并生成

实际上如果i确实大于4则失败。但是在真实机器上的实际C

编译器上,扁平访问通常会起作用。

根据这种情况,就像在冰冻的池塘里滑冰一样,有人

已经推出了dang呃 - 薄冰标志。你可能会很好,但是如果你陷入僵局并冻死,你就会知道谁应该承担责任。 :-))

在这种情况下,幸运的是 - 目前尚不清楚这是否是b $ b祝你好运或运气不好 - 如果上面的代码编译,则值

pfunc()返回将展平数组,这个值将被重新折叠。通过转让给pd。折叠,旋转后,

并且可能会破坏价值,代码将继续访问

arr [0] [3]和arr [1] [2]指针值现在存储在

" pd"中。这两个元素是arr。应分别包含20和9

;这就是你实际看到的:


它编译并正常工作,但编译器我已经尝试过了
警告我非法转换指针类型 ;或可疑的指针转换或关于:

pd = pfunc();


C标准仅表示诊断。是必须的。一个警告

足以作为一个诊断,就像编译器非常快地旋转

CD-ROM一样,它会发出可怕的呜呜声(如

只要编译器的文档说得那么多)。完全中止编译的错误

也是一种有效的诊断。

我很难过。我认为我的语法是正确的,文献中没有什么
或者这个小组的常见问题解答告诉我其他情况;然而,
如果我将声明和初始化结合起来:

int(* pd)[5] = pfunc();

。 。 。警告消失了。这有什么用呢?
int *pfunc(void);
This declares pfunc as a function taking no arguments and returning
"int *", or "pointer to int". A value of type "pointer to int" can
(but does not necessarily) point to the first of one or more "int"s
in sequence, or even into the middle of such a sequence:

int *p1;
int x, y[4];

p1 = NULL; /* p1 does not point to any "int"s */
p1 = &x; /* p1 points to a single "int" */
p1 = &y[0]; /* p1 points to the first of 4 ints */
p1 = &y[1]; /* p1 points to the second of 4 ints, so p1[-1] is y[0] */

Presumably pfunc() will return a pointer to a single int, or to the
first of a sequence of "int"s.
int main(void)
{
int (*pd)[5];
(Very good definition of main(), by the way. :-) )

"pd" has type "pointer to array 5 of int". As with p1 above, it can
(not necessarily "does") point to the first of one or more "array 5
of int"s in sequence.
pd = pfunc();
Type mismatch: pfunc() returns a pointer to an int, or some int
within a sequence of "int"s. "pd" needs to point to an "array 5
of int", or the first of a sequence of "array 5 of int"s.
/* Should return 20 and 9 */
printf("\nDigits are: %d and %d", *(*(pd + 0) + 3), *(*(pd + 1) + 2) );
This could be written more clearly as:

printf("\nDigits are: %d and %d", pd[0][3], pd[1][2]);
return 0;
For strict portability, make sure any output is newline-terminated
(e.g., replace the above printf format "\n..." with "...\n", or
"\n...\n" if you like the extra blank line for some reason).
}

int *pfunc(void)
{
static int arr[2][5] = {{5, 10, 15, 20, 25}, {3, 6, 9, 12, 15}};
"arr" has type "array 2 of array 5 of int". That is, it is an array
of 2 "things", where each of those "things" is an "array 5 of int".
arr[0] is the first of those things and arr[1] is the second.
return(*arr);
}
Aside: the parentheses here are unnecessary, albeit harmless. The
syntax for "return" statements that return a value is:

return expression;

and of course expressions can be parenthesized. In any case, the
effect is to return a value.

*arr is one way to write arr[0]. This names the entire "array 5
of int" containing the sequence {5, 10, 15, 20, 25}. Whenever you
name an array object in a place where a value is required, C compilers
will produce, as a value, the address of the first element of that
array. Hence:

return arr[0];

"means" the same thing as:

return &arr[0][0];

Hence pfunc() returns a pointer to the "int" holding the value 5
(namely arr[0][0]), which is of course the first of five "int"s
in sequence.

Because C''s arrays are always "a sequence of identically-typed
elements with no gaps in between"[%], this sequence of 5 "int"s is
going to be followed by the sequence of 5 "int"s that make up the
object arr[1]. That is, if you can somehow "flatten out" the array,
you get 2 * 5 = 10 "int"s in a row, holding the sequence {5, 10,
15, 20, 25, 3, 6, 9, 12, 15}.
-----
% Or more precisely, if there are gaps, they have to be invisible
as long as you stick to code with defined behavior.
-----

(The C standard does not promise that accessing the array in this
"flattened" manner will always work. There may be some rare
situations in which a clever C compiler tracks array-bounds
information so that it "knows" that, e.g., arr[0][i] can never have
a value of "i" greater than 4, and generates machine code that
actually fails if "i" really is greater than 4. But on real C
compilers on real machines, the flattened access usually does work.
Depending on this is like skating across a frozen pond where someone
has put out a "danger -- thin ice" sign. You will probably be
fine, but if you fall in and freeze to death, you will know who to
blame. :-) )

In this case, with some luck -- it is not clear whether this is
"good luck" or "bad luck" -- if the above code compiles, the value
pfunc() returns will "flatten out" the array, and this value will
be "re-folded" by the assignment to "pd". Having folded, spindled,
and perhaps mutilated the value, the code will go on to access
arr[0][3] and arr[1][2] through the pointer value now stored in
"pd". These two elements of "arr" should contain 20 and 9
respectively; and that is what you actually saw:

It compiles and works correctly, but the compilers I''ve tried it
on warn me of "illegal conversion of pointer type" or "suspicious
pointer conversion" regarding:

pd = pfunc();
The C standard says only that "a diagnostic" is required. A warning
suffices as a diagnostic, as does having the compiler spin the
CD-ROM really fast so that it makes a horrible whining sound (as
long as the compiler''s documentation says as much). An "error"
that aborts compilation entirely is also a valid diagnostic.
I''m stumped. I think my syntax is correct, and there''s nothing
in the literature or this group''s FAQ that tells me otherwise; yet,
if I combine the declaration and initialisation to:

int (*pd)[5] = pfunc();

. . . the warnings go away. What''s up with that?




这表示编译器存在错误,因为诊断仍然需要
。 />

正确要做的事情(至少某些版本的右)是让bfunc()返回正确类型值的
。这需要一些丑陋的语法,或者使用C'的typedef。 type-alias-creating

facility。


使用typedef - 它只交换一个丑陋的语法,用于

不同丑陋语法,在我个人看来:-) - 我们得到的东西

是这样的:


#include< stdio.h>


typedef int Zog [5]; / * Zog现在是int [5]的别名* /


Zog * pfunc(void);


int main(void) {

Zog * pd;


pd = pfunc();

printf("%d和%d \ n",pd [0] [3],pd [1] [2]);

返回0;

}


Zog * pfunc(void){

static int arr [2] [5] = {{5,10,15,20,25},{3,6,9,12,15 } ;;


返回arr; / *或return& arr [0]; * /

}


要消除typedef,我们只需要将其展开 - 但现在我们需要括号b / b
和[5]处于尴尬的地方,与

原始定义的pd相同。在main()中:


int(* pfunc(void))[5];


int main(void){

int(* pd)[5];


pd = pfunc();

printf("%d和%d \\ n) \\ n",pd [0] [3],pd [1] [2]);

返回0;

}


int(* pfunc(void))[5] {

static int arr [2] [5] = {{5,10,15,20,25},{3,6 ,9,12,15}};


return arr; / *或return& arr [0]; * /

}


注意(唉)在C89中,pfunc()只能返回一个指针(

)几个中的第一个)int的数组5。所以我们可以改变arr

" static int arr [123] [5]",或static int arr [42] [5],但绝不要

"例如,static int arr [2] [7]"。 C99'的可变长度

阵列和可变地修改。类型解决了这个特殊的问题。


除此之外:我一般不喜欢typedef,而且因为C'的特殊性,我不喜欢

数组类型的typedef数组的处理。

与其他所有数据类型不同,你*必须*知道某些类型是否为数组类型是为了预测参数的行为,

并知道返回该类型的值是否可以。

是给定Zog的。上面的typedef,以下是无效的C:


Zog f(无效){

Zog结果;


while(need_more_work())

fill_it_in(& result);

返回结果;

}


但是如果我们要替换typedef行,例如:


struct zog {int val [5]; };

typedef struct zog Zog;


然后上面的函数f()会突然变为有效C.同样,

如果我们不知道是否Morgle是数组类型的typedef,

我们无法判断是否可以简化以下内容:


void操作(无效){

Morgle a,b;


init(& a);

memcpy(& b,& a,sizeof a); / * ???我们需要这个吗? * /


而(more_to_do())

frob(a);


/ *确保frob ()没有修改a。 * /

if(memcmp(& a,& b)!= 0)

printf(" alas!alack!\ n");

}


如果Morgle *不是*数组类型,frob()将无法修改

a,因为frob()取* a *的*值*,而不是

" a"的地址。在这种情况下,副本在b中。是没有意义的,memcmp()

永远不会显示它们不同,所以我们不需要副本。

但是如果Morgle *是*数组类型,frob( )收到一个指向

第一个元素a的指针,并且能够修改a。


(在某些情况下我们可以使用const来承诺,弱,frob()

不会修改a,即使它获得指向第一个元素的指针;

但这个承诺可以被违反,并且在某些情况下添加const

无论如何都是不合适的。我认为最好避免这种情况

完全。)


(问题的核心在于C对阵阵列特别是特别。

因此,重要的是要知道是否有些据称是$

抽象类型实际上是一个数组类型。如果是这样,它将不会像其他类型的行为那样表现出来.C'的结构类型* do *表现

恰当,s o在极限情况下,所有抽象数据类型应该是

structs。)


即使我分解并使用的typedef" :-)用于

指针到函数类型。考虑信号,它需要两个

参数:


- 一个,一个int指定哪个信号,和

- 另一个,指向信号函数的指针


并返回一个值:


- 指向信号处理函数的指针


其中重复的类型 - 指向信号处理函数的指针

本身就是一个指向函数的指针 - 取回 - 返回-void,

或void(*)(int),带有笨拙的括号,

星号和参数类型。如果我们写下这个特定类型的一个typedef

,我们可以使用它两次得到:


typedef void(* Sig_func_ptr)(int);

Sig_func_ptr信号(int sig,Sig_func_ptr func);


当然,标准标题< signal.h>不允许使用用户命名空间中的
名称,因此大多数实现者都会在线内扩展

类型,并省略参数名称,给出:


void(* signal(int,void(*)(int)))(int);


充其量令人困惑。如果你是实现者,并且

去编写函数的定义,那就更糟了:


void(* signal(int sig, void(* func)(int)))(int){

void(* old(int,void(*)(int)))(int);


if(sig< __MIN_SIGNO || sig> = __MAX_SIGNO)

返回SIG_ERR;


这里有某种信号原子性魔法;


old = __sigtable [sig - __MIN_SIGNO];

/ *

*可能需要额外的工作,具体取决于sig和/或是否

* func == SIG_DFL或SIG_IGN。例如,而不是

*疯狂的堆栈顶部蹦床代码。那个BSD系统(使用

*到?)使用,我们可能会这样做:

*

* if(func == SIG_DFL || func == SIG_IGN)

* kernel_entry = func;

* else

* kernel_entry = __sigtramp;

* __sig_syscall(sig,kernel_entry,以及任何,其他,args);

*

*然后本地信号表包含userland处理程序,

*内核被告知跳转到库中的蹦床代码

*,无论在哪里加载。

*现在库总是自动匹配自己,甚至

*以及未来的版本更改,例如,为了节省额外的状态。

*

*我相信Sun做了这样的事情返回SunOS 4.x

*或5.0左右。

* /

__sigtable [sig - MIN_SIGNO] = func;


这里的原子性更多,包括检查未决信号;


返回旧;

}


当然,信号(及其相关的原子性问题,操作系统交互和硬件依赖性)是相对较深的

魔术"首先。

-

现实生活中:风河系统Chris Torek

美国犹他州盐湖城(40°39.22''N,111°50.29''W)+1 801 277 2603

电子邮件:忘了它 http://web.torek.net/torek/index.html

阅读电子邮件就像搜索食物一样垃圾邮件,感谢垃圾邮件发送者。



That would indicate a bug in the compiler, as a diagnostic is
still required.

The "right" thing to do (for some version of "right" at least) is
to have pfunc() return a value of the correct type. This requires
some ugly syntax, or resorting to C''s "typedef" type-alias-creating
facility.

Using a typedef -- which merely exchanges one ugly syntax for a
different ugly syntax, in my personal opinion :-) -- we get something
like this:

#include <stdio.h>

typedef int Zog[5]; /* Zog is now an alias for int[5] */

Zog *pfunc(void);

int main(void) {
Zog *pd;

pd = pfunc();
printf("%d and %d\n", pd[0][3], pd[1][2]);
return 0;
}

Zog *pfunc(void) {
static int arr[2][5] = {{5, 10, 15, 20, 25}, {3, 6, 9, 12, 15}};

return arr; /* or return &arr[0]; */
}

To eliminate the typedef, we just have to expand it out -- but now
we need parentheses and "[5]"s in awkward places, as with the
original definition for "pd" in main():

int (*pfunc(void))[5];

int main(void) {
int (*pd)[5];

pd = pfunc();
printf("%d and %d\n", pd[0][3], pd[1][2]);
return 0;
}

int (*pfunc(void))[5] {
static int arr[2][5] = {{5, 10, 15, 20, 25}, {3, 6, 9, 12, 15}};

return arr; /* or return &arr[0]; */
}

Note that (alas) in C89, pfunc() can only return a pointer to (the
first of several of) "array 5 of int"s. So we can change "arr" to
"static int arr[123][5]", or "static int arr[42][5]", but never to
"static int arr[2][7]", for instance. C99''s "variable-length
arrays" and "variably modified" types solve this particular problem.

Aside: I dislike typedefs in general, and I dislike typedefs for
array types even more because of C''s peculiar treatment of arrays.
Unlike every other data type, you *must* know whether some type
is an array type in order to predict the behavior of arguments,
and know whether it is OK to return a value of that type. That
is, given the "Zog" typedef above, the following is not valid C:

Zog f(void) {
Zog result;

while (need_more_work())
fill_it_in(&result);
return result;
}

But if we were to replace the typedef line with, e.g.:

struct zog { int val[5]; };
typedef struct zog Zog;

then the function f() above would suddenly become valid C. Similarly,
if we have no idea whether "Morgle" is a typedef for an array type,
we cannot tell whether the following can be simplified:

void operate(void) {
Morgle a, b;

init(&a);
memcpy(&b, &a, sizeof a); /* ??? do we need this ? */

while (more_to_do())
frob(a);

/* make sure frob() did not modify "a" */
if (memcmp(&a, &b) != 0)
printf("alas! alack!\n");
}

If Morgle is *not* an array type, frob() will be unable to modify
"a", because frob() takes the *value* of "a", not the address of
"a". In this case, the copy in "b" is pointless and the memcmp()
will never show them as different, so we do not need the copy.
But if Morgle *is* an array type, frob() receives a pointer to the
first element of "a", and is able to modify "a".

(In some cases we can use "const" to promise, weakly, that frob()
will not modify "a" even if it gets a pointer to the first element;
but this promise can be violated, and in some cases adding "const"
is inappropriate anyway. I think it is better to avoid the situation
entirely.)

(The heart of the problem is really that C treats arrays "specially".
Because of this, it is important to know whether some purportedly
abstract type is in fact an array type. If so, it will not behave
the way other types behave. C''s structure types *do* behave
"properly", so in the limit, all abstract data types should be
"struct"s.)

The one place where even I break down and use "typedef" :-) is for
pointer-to-function types. Consider "signal", which takes two
parameters:

- one, an int specifying which signal, and
- the other, a pointer to a signal-hanlding function

and returns one value:

- a pointer to a signal-handling function

where the repeated type -- "pointer to signal-handling function"
is itself a pointer-to-function-taking-int-and-returning-void,
or "void (*)(int)", complete with awkwardly-placed parentheses,
asterisks, and parameter types. If we write down one typedef for
this particular type, we can then use it twice and get:

typedef void (*Sig_func_ptr)(int);
Sig_func_ptr signal(int sig, Sig_func_ptr func);

Of course, the standard header <signal.h> is not allowed to use
names that are in the user''s namespace, so most implementors expand
the types in-line, and omit the parameter names, giving:

void (*signal(int, void (*)(int)))(int);

which is confusing at best. If you are the implementor, and
go to write the function''s definition, it gets even worse:

void (*signal(int sig, void (*func)(int)))(int) {
void (*old(int, void (*)(int)))(int);

if (sig < __MIN_SIGNO || sig >= __MAX_SIGNO)
return SIG_ERR;

some sort of signal atomicity magic here;

old = __sigtable[sig - __MIN_SIGNO];
/*
* May need additional work depending on sig and/or whether
* func == SIG_DFL or SIG_IGN. For instance, instead of the
* crazy top-of-stack "trampoline code" that BSD systems (used
* to?) use, we might do something like this:
*
* if (func == SIG_DFL || func == SIG_IGN)
* kernel_entry = func;
* else
* kernel_entry = __sigtramp;
* __sig_syscall(sig, kernel_entry, and, any, other, args);
*
* Then the local signal table contains the userland handler,
* while the kernel is told to jump to the trampoline code
* in the library, no matter where that has been loaded.
* Now the library always automatically matches itself, even
* with future version changes, e.g., to save additional state.
*
* I believe Sun did something like this way back in SunOS 4.x
* or 5.0 or so.
*/
__sigtable[sig - MIN_SIGNO] = func;

more atomicity here including check for pending signals;

return old;
}

Of course, signals (with their associated atomicity issues, operating
system interactions, and hardware dependencies) are "relatively deep
magic" in the first place.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22''N, 111°50.29''W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.


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

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