memcpy和指针/数组混淆的问题 - 再次 [英] problem with memcpy and pointers/arrays confusion - again

查看:116
本文介绍了memcpy和指针/数组混淆的问题 - 再次的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述




我在C编程方面相对较新,即使我已多次阅读

指针和数组,对我来说这是一个有点混乱的话题

- 至少在这一刻:


----

1)这三个陈述之间的区别是什么:


(i)memcpy(& b,& KoefD,n); //这在我的代码中的某处工作


(ii)memcpy(& b [0],& KoefD [0],n); //但这不是
(iii)memcpy(b,KoefD,n); //那么这是什么意思呢?

注意:b定义如下:


double * b =(double *)malloc( sizeof(double)*(n + 1));





KoefD是从中调用的子函数的参数

main()。它的原型(在main函数中)是这样的:


void sub_function(int n,const double * KoefD);


我明白这个&给出了指针的物理地址

本身...我认为这与& b [0](第一个

元素)是一回事 - 但它似乎不是......

2)为什么这样做:


free(indx); //免费一维阵列


但这不是吗?


免费(二);


---------

indx是:

unsigned long * indx =(unsigned long *)malloc((n + 1)* sizeof(未签名

长));


b是:

double * b =(double *)malloc( sizeof(double)*(n + 1));

我希望我不必小块地削减我的程序以显示

这些问题是实际上我现在遇到的一些问题和它可能是我误解了什么,但任何评论都会很大

赞赏...


如果必须的话,我会把我的程序剪下来,这样你就可以复制/粘贴,但是如果我能自己弄清楚错误的话,那将会更容易。

最好的问候/ Med venlig hilsen

Martin J?rgensen


-

----- -------------------------------------------------- --------------------

Martin J?rgensen的故乡 - http://www.martinjoergensen.dk

推荐答案

Martin J?rgensen schrieb:
Martin J?rgensen schrieb:


我是一个相对较新的C编程,即使我读过
指针和数组很多次,对我来说这是一个有点混乱的话题 - 至少在这一刻:

----
1 )这三个陈述之间的区别是什么:


请在问题面前提供类型 - 否则,

很难回答。


double * b;

const double& KoefD;

int n;
(i)memcpy(& ; b,& KoefD,n); //这在我的代码中的某处工作


从指针KoefD

的地址开始复制n个字节到b的地址。如果n == sizeof KoefD(即指针的大小为

),则相当于b = KoefD。

如果n> sizeof KoefD,您可能会从不属于您的程序的
存储中复制或移动 - 如果您好b / b
很幸运,则会出现段错误/访问冲突或类似的。

如果n< sizeof KoefD,你可能最终得到一个陷阱

表示或不属于你的程序的地址

存储在b中。

注意:如果KoefD的类型数组N为双,

N> = n / sizeof(double)和(n%sizeof(double))== 0和

b属于类型数组M的双倍,M> = n / sizeof(双),

然后这将起作用。


(ii)memcpy(& b) [0],& KoefD [0],n); //但这不是

(iii)memcpy(b,KoefD,n); //这是什么意思呢?


这两个是等价的,只要n是KoefD指向的存储空间的

并且

就可以工作0 ==(n%sizeof(double))。

注意:b定义为:

double * b =(double *)malloc(sizeof(double) *(n + 1));


1)请不要转换malloc()的返回值。

这已经向您解释过至少一次。使用malloc()

是这样的:

double * b = malloc((n + 1)* sizeof * b);

2)请注意,你只是memcpy()只分配了

存储的一部分(你忘记了第n + 1个元素),如果

sizeof(double)!= 1,你可能没有达到你想要的价格。

memcpy(b,KoefD,(n + 1)* sizeof KoefD [0])

应该适合你。

和/ /
KoefD是从
main()中调用的子函数的参数。它的原型(在main-function中)是这样的:

void sub_function(int n,const double * KoefD);

我明白这个&& ;"给出了指针的物理地址
本身......我认为这与& b [0](第一个
元素)是一回事 - 但它看起来并不像是....


编号(i)只给出与(ii)和(iii)相同的地址,如果Koef和

b是数组 - "类型"但地址仍然不同。


2)为什么这样做:

free(indx); //免费一维阵列

但这不是吗?

免费(二);

---------

indx是:
unsigned long * indx =(unsigned long *)malloc((n + 1)* sizeof(unsigned
long));

b是:
double * b =(double *)malloc(sizeof(double)*(n + 1));


与malloc()相同。

如果您需要演员表,那么您要么忘了#include< stdio.h>

或者你在C ++模式下编译 - 两者都可能导致细微的错误。


另一件事:分配size + 1通常只需要

字符数组,用于保存长度为< = size的字符串。

如果你的代码需要它(例如因为你更喜欢基于1的数组) ),

一旦你获得阵列阵列,你就可能会让自己头疼得厉害 - 你几乎被一个人邀请了

类型的错误。


如果免费(指针)不起作用,那么你通常有

- 更改指针= malloc之间的指针( ....)和自由(指针);或者

- 通过写入分配的

存储边界或free()多次使用相同的指针值来破坏已分配的内存处理。


要调试,printf("%p\ n",(void *)b);直接在免费(b)之前分配b和

之后;确保它不是第一个错误。

然后开始检查您对已分配存储的访问。如果它有意义,请在free()调用后直接将free()ed指针设置为NULL。


我希望我没有必要小块地减少了我的程序,以表明这些问题实际上是我现在遇到的一些问题而且它可能是我误解了一些问题,但任何评论都会非常感激......

如果必须的话,我会削减我的程序,这样你就可以复制/粘贴,但是如果我能自己弄清楚错误会更容易。
Hi,

I''m relatively new with C-programming and even though I''ve read about
pointers and arrays many times, it''s a topic that is a little confusing
to me - at least at this moment:

----
1) What''s the difference between these 3 statements:
Please provide the types before the question -- otherwise,
it is hard to answer.

double *b;
const double &KoefD;
int n;
(i) memcpy(&b, &KoefD, n); // this works somewhere in my code
Copy n byte starting at the address of the pointer KoefD
to the address of b. If n == sizeof KoefD (i.e. the size of
the pointer), then this is equivalent to b = KoefD.
If n > sizeof KoefD, you may run off copying from or to
storage which does not belong to your programme -- if you
are lucky, you get a segfault/access violation or similar.
If n < sizeof KoefD, you may end up with a trap
representation or an address not belonging to your programme
stored in b.
Note: If KoefD were of type array N of double with
N >= n/sizeof (double) and (n%sizeof (double)) == 0 and
b were of type array M of double with M >= n/sizeof (double),
then this would work.

(ii) memcpy(&b[0], &KoefD[0], n); // but this doesn''t

(iii) memcpy(b, KoefD, n); // what''s the meaning of this then?
These two are equivalent and should work as long as n is the
size of the storage pointed to by KoefD and
0 == (n%sizeof (double)).
N.B: b is defined such that:

double *b = (double *) malloc(sizeof(double) * (n+1));
1) Please do not cast the return value of malloc().
This has been explained to you at least once. Use malloc()
like this:
double *b = malloc((n+1) * sizeof *b);
2) Note that you are memcpy()ing only part of the allocated
storage (you forget the n+1st element) and that if
sizeof(double) != 1, you probably do not achieve what you
want.
memcpy(b, KoefD, (n+1) * sizeof KoefD[0])
should be about right for you.

and

KoefD is an argument to a sub-function that is called from within
main(). It''s prototype (in main-function) is something like:

void sub_function(int n, const double *KoefD);

I understand that this "&" gives the physical address of the pointer
itself... I would assume that was the same thing as &b[0] (the first
element) - but it doesn''t seem like it is....
No. (i) gives only the same address as (ii) and (iii) if Koef and
b are arrays -- the "type" of the address is still different, though.

2) Why does this work:

free(indx); // free 1D array

But this doesn''t?

free(b);

---------

indx is:
unsigned long *indx = (unsigned long *) malloc( (n+1)*sizeof(unsigned
long) );

b is:
double *b = (double *) malloc(sizeof(double) * (n+1));
Same about malloc().
If you need the cast, then you either forgot to #include <stdio.h>
or you are compiling in C++ mode -- both can lead to subtle bugs.

Another thing: Allocating "size + 1" usually only is necessary for
character arrays intended to hold strings of length <= size.
If you need it for your code (e.g. because you prefer 1-based arrays),
you may be in for giving yourself a heavy headache as soon as you
get to arrays of arrays -- you are practically inviting off by one
type of errors.

If free(pointer) does not work, then you usually have either
- changed pointer between pointer = malloc(....) and free(pointer); or
- have corrupted allocated memory handling by writing over allocated
storage bounds or free()ing the same pointer value more than once.

To debug, printf("%p\n", (void *)b); directly after allocating b and
directly before free(b); to make sure it is not the first error.
Then start checking your accesses of allocated storage. If it makes
sense, set free()ed pointers to NULL directly after the free() call.

I hope I don''t have to cut down my program in small pieces to show that
these questions are actually some problems I struggle with now and it
might be I misunderstood something, but any comments would be greatly
appreciated...

If I have to, I''ll cut my program down so you can just copy/paste, but
it would be much easier if I could figure out the error myself.




在这种情况下,可能的错误原因提供了自己,但我可能完全关闭了
- 所以,是的,去寻找最小的编译示例。

干杯

Michael

-

电子邮件:我的是/ at / gmx / dot / de address。



In this case, a probable error cause offers itself but I may be
completely off -- so, yes, go for the minimal compiling example.
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.


Michael Mair写道:
Michael Mair wrote:
Martin J?rgensen schrieb:
-snip-

请在问题面前提供类型 - 否则,

好​​的,对不起。如你所知,我在这个小组中相对较新,所以

在我想之前没有人告诉过我,但从现在开始我会记住这一点。


-snip-
Martin J?rgensen schrieb: -snip-
Please provide the types before the question -- otherwise,
it is hard to answer.
Ok, sorry for that. As you know, I''m relatively new in this group so
nobody ever told me that before I think, but I''ll remember that from now on.

-snip-
注意:b的定义是:

double * b =(double * )malloc(sizeof(double)*(n + 1));
N.B: b is defined such that:

double *b = (double *) malloc(sizeof(double) * (n+1));



1)请不要转换malloc()的返回值。
这已被解释为你至少一次。像这样使用malloc()

double * b = malloc((n + 1)* sizeof * b);


1) Please do not cast the return value of malloc().
This has been explained to you at least once. Use malloc()
like this:
double *b = malloc((n+1) * sizeof *b);




对不起,但我忘了AFAIR只有一个人告诉我。

他并没有解释这个问题,所以我现在引用:(Robin Haigh) -

你由于

下标基数从1变为0,所以在这里得到了无关紧要的复杂情况。你可以放弃演员表。


所以我''很遗憾地问这个演员有什么问题?


我可以告诉你为什么它在我的代码中:这是因为我有一些源代码

来自一个在C编程方面经验丰富的人。我可以

然后改变它(并且会这样做,因为我确定你是对的,即使我不知道这个解释)。 ..

2)请注意,你只是memcpy()只分配了
存储的一部分(你忘记了第n + 1个元素),如果
sizeof(double) != 1,你可能没有实现你想要的东西。
memcpy(b,KoefD,(n + 1)* sizeof KoefD [0])
应该适合你。


Douh!当然,我忘了将尺寸乘以KoefD [0] ... ...

愚蠢的初学者的错误,我想。



Sorry, but I forgot. AFAIR only one person told me that.
And he didn''t explain the problem, so I''m citing now: (Robin Haigh) -
"You''ve got irrelevant complications here because of the change of
subscript base from 1 to 0. You can drop the casts".

So I''m sorry to ask but what was wrong with doing this cast?

I can tell you why it''s in my code: It''s because I have some source code
from a guy who is a lot more experienced that me in C-programming. I can
change it however (and will do so, because I''m sure you''re right even
though I don''t know the explanation)...
2) Note that you are memcpy()ing only part of the allocated
storage (you forget the n+1st element) and that if
sizeof(double) != 1, you probably do not achieve what you
want.
memcpy(b, KoefD, (n+1) * sizeof KoefD[0])
should be about right for you.
Douh! Ofcourse I forgot to multiply the size with sizeof KoefD[0]...
Stupid beginner''s mistake, I guess.

KoefD是从
main()内部调用的子函数的参数。它的原型(在main-function中)是这样的:

void sub_function(int n,const double * KoefD);

我明白这个&& ;"给出了指针的物理地址
本身......我认为这与& b [0](第一个
元素)是一回事 - 但它看起来并不像是....
KoefD is an argument to a sub-function that is called from within
main(). It''s prototype (in main-function) is something like:

void sub_function(int n, const double *KoefD);

I understand that this "&" gives the physical address of the pointer
itself... I would assume that was the same thing as &b[0] (the first
element) - but it doesn''t seem like it is....



编号(i)只给出与(ii)和(iii)相同的地址,如果Koef和
b是数组 - 类型 ;但是地址仍然不同。


No. (i) gives only the same address as (ii) and (iii) if Koef and
b are arrays -- the "type" of the address is still different, though.




它们是数组...



They are arrays...

2)为什么这样做:

免费(indx); //免费一维阵列
但这不是吗?

免费(二);

---------

indx是:
unsigned long * indx =(unsigned long *)malloc((n + 1)* sizeof(unsigned
long));

b是:
double * b =(double *)malloc(sizeof(double)*(n + 1));
2) Why does this work:

free(indx); // free 1D array
But this doesn''t?

free(b);

---------

indx is:
unsigned long *indx = (unsigned long *) malloc( (n+1)*sizeof(unsigned
long) );

b is:
double *b = (double *) malloc(sizeof(double) * (n+1));



与malloc()相同。
如果你需要演员,然后你忘了#include< stdio.h>
或者你正在用C ++模式进行编译 - 两者都会导致微妙的错误。


Same about malloc().
If you need the cast, then you either forgot to #include <stdio.h>
or you are compiling in C++ mode -- both can lead to subtle bugs.




我认为错误是我已经尝试过memcpy(& b,& KoefD,

....)哪个是错误的......错误消失了我把它改成memcpy(b,KoefD,......)之后现在是



另一件事:分配size + 1通常只对于用于保存长度为< = size的字符串的
字符数组是必需的。
如果您的代码需要它(例如,因为您更喜欢基于1的数组),
您可以一旦你进入阵列阵列就会让你自己头疼 - 你实际上是在接受一种类型的错误。


是的,我一直在努力使用以偏移量1

而非偏移0开始的阵列阵列。但我想我现在可以管理它了(虽然你肯定是有点复杂的但是b $ b ...我只记得在内存位置添加

row * cols * sizeof(type)指向。

如果free(指针)不起作用,那么你通常要么改变了指针= malloc(....)和free(指针)之间的指针。或者
- 通过写入分配的存储边界或多次使用相同的指针值来破坏已分配的内存处理。


认为一定是因为memcpy错误导致内存损坏

位置...

要调试,printf( %p \ n,(void *)b);直接在免费(b)之前分配b和
之后;确保它不是第一个错误。


好​​提示 - 我会记住的。可能需要另一次。

然后开始检查您对已分配存储的访问。如果它有意义,请在free()调用后直接将free()ed指针设置为NULL。



I think the error was that I''ve experimented with memcpy(&b, &KoefD,
....) which ofcourse is wrong... The error disappeared by itself now
after I changed it to memcpy(b, KoefD, ...)
Another thing: Allocating "size + 1" usually only is necessary for
character arrays intended to hold strings of length <= size.
If you need it for your code (e.g. because you prefer 1-based arrays),
you may be in for giving yourself a heavy headache as soon as you
get to arrays of arrays -- you are practically inviting off by one
type of errors.
Yeah, I''ve been struggling with arrays of arrays that starts at offset 1
instead of offset 0. But I think I can manage it now (although you''re
right that it is a little complicated)... I just remember to add
row*cols*sizeof(type) to the memory location pointed to.
If free(pointer) does not work, then you usually have either
- changed pointer between pointer = malloc(....) and free(pointer); or
- have corrupted allocated memory handling by writing over allocated
storage bounds or free()ing the same pointer value more than once.
Think it must have been corrupt memory due to memcpy to the wrong
location...
To debug, printf("%p\n", (void *)b); directly after allocating b and
directly before free(b); to make sure it is not the first error.
Good tip - I''ll remember that. Might be necessary another time.
Then start checking your accesses of allocated storage. If it makes
sense, set free()ed pointers to NULL directly after the free() call.




它会产生什么影响?



What effect will that have?

我希望我不必小编我的程序以显示这些问题实际上是我现在遇到的一些问题
可能是我误解了一些东西,但任何评论都会非常感激......

如果必须的话,我会削减我的程序,这样你就可以只是复制/粘贴,但是如果我能自己弄清楚错误会更容易。
I hope I don''t have to cut down my program in small pieces to show
that these questions are actually some problems I struggle with now
and it might be I misunderstood something, but any comments would be
greatly appreciated...

If I have to, I''ll cut my program down so you can just copy/paste, but
it would be much easier if I could figure out the error myself.



在这种情况下,可能的错误原因提供了自己,但我可能是
完全关闭 - 所以,是的,去寻找最小的编译示例。


In this case, a probable error cause offers itself but I may be
completely off -- so, yes, go for the minimal compiling example.




你是完全正确的。如上所述:memcpy(&,&,n)不是我需要的b $ b而是需要memcpy(blabla,blabla,n * sizeof(某物))

所以这基本上给我带来了一些麻烦,因为我忘了将
n乘以sizeof(double)8字节。


另一件事:


为了节省我的源代码空间,我不会聪明/可能

我这样做(未经测试 - 使用来自的建议a

前一个帖子):


- - - - - - - - - - - - - - - - - - - -

#include< stdio.h>

#include< stdlib.h>


int main()

{

unsigned long int total_mem_used = 0; //柜台

int N = 20; //无论多少元素


int * int_array = int_allocate_mem((N + 1)* sizeof(int),__ FILE __,

__LINE __,& total_mem );

printf(" int_array占用:内存中的%i字节,* int_array [N]);


printf("总内存)职业是:%li bytes",* total_mem);


free_mem(int_array);


退出(0);

}


//(返回类型void ???不应该是int *?)


(返回type)int_allocate_mem(size_t size,char * file,int line,

* total_mem)

{

int * int_ptr = malloc(size) ;

if(int_ptr == NULL)

{

fprintf(stderr,"%s:line%d,malloc(%ld) )failed.\\\
,文件,

行,大小);

退出(EXIT_FAILURE);

}


int_ptr [N] =大小; //为此指针保存分配的内存

total_mem + = size; //更新分配的总内存,直到现在


返回int_ptr;

}

- - - - - - - - - - - - - - - - - - - -


我还希望有一个double_allocate_mem((N + 1)* sizeof(双),

__FILE __,_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $也是在数组的开头,但是我认为它更容易把它放到最后)。


这样,我可以更容易调试和记录整个程序中的内存占用

..这真的*真的很好

我想...建议/评论?我希望...

致以诚挚的问候/ Med venlig hilsen

Martin J?rgensen


-

----------------------------------------------- ----------------------------

Martin J?rgensen的故乡 - http://www.martinjoergensen.dk


Martin J? rgensen说:
Martin J?rgensen said:
所以我很遗憾地问这个演员怎么了?

我可以告诉你为什么这样做我的代码:这是因为我有一些源代码来自一个在C编程方面比我更有经验的人。我可以改变它(并且会这样做,因为我确定你是对的,但我不知道解释)...
So I''m sorry to ask but what was wrong with doing this cast?

I can tell you why it''s in my code: It''s because I have some source code
from a guy who is a lot more experienced that me in C-programming. I can
change it however (and will do so, because I''m sure you''re right even
though I don''t know the explanation)...




这里给你一个解释:


------------------- -------------------------------------------------- -


施法


隐含转换


在C编程语言中,有两种

不同类型表达式之间的转换。第一个由编译器提供

本身。这称为隐式转换。这是'

使用的一个例子:


long int foo = 314159265L;

double bar = foo;


这种转换当然非常自然。事实上,早在K& R2的第12页(其中转换

从浮动到双倍)就发生了这样的转换。

这样的转换。这种转换被编织成语言的结构,并且是如此常见和自然,以至于我们经常没有注意到它们的价值。


显式转换(强制转换)


但是,还有另一种方法可以将表达式从一种类型转换为

另一种类型;第二种方法称为显式转换或强制转换。

这是一个演员的例子:


IsLowerCase = islower((unsigned char) )* p);


顺便说一句,这个演员阵容很好。在某些情况下,

显式转换或演员表是一种便利,它允许我们写出比其他情况更好,更清晰的代码。然而演员阵容很难理解。


出于某种原因,演员在C程序员中非常受欢迎。这就像是一个魔杖,它可以神奇地将一种类型转换成另一种类型,无论语义,逻辑还是常识,都可以将它变成另一种类型。事实上,在投射表达式时,有很多(如果有的话)感觉已经存在了一个完美的

足够的隐式转换。根据这个经验法则,很少有例外。

。例如,考虑以下代码:


#include< math.h>

long GetHypotenuse(长高,长基)

{

返回sqrt(高度*高度+基数*基数);

}


有些编译器会抱怨这个代码,认为sqrt返回一个

double,并且将这样的值分配给long可能会导致
信息的丢失。嗯,这是真的。但是,如果打算这样丢失

信息也是如此,那就没有问题了(因为我们只对

感兴趣结果的整数部分);如果不打算丢失这些信息,那么我们真的应该关注

编译器的投诉。


投射为诊断抑制器


我们经常可以通过使用演员来抑制警告:


#include< math.h> ;

长GetHypotenuse(长身高,长底)

{

返回(长)sqrt(身高*身高+基数*基数);

}


演员实际上告诉编译器:我知道我在做什么!所以闭嘴

!许多C程序员都这样做(即使是那些只认为他们知道他们正在做什么的人)。演员是否合理?好吧,在这种情况下,

有一个(可能是假的)理由,不是技术术语而是

纯粹是为了获得一个干净的编译。唉,这个借口是用来证明很多不必要的演员。是的,确实很好看,干净的

汇编是很好的。但是如果我们只是通过扼杀编译器来实现这种状态,而不了解这种情况可能带来的影响,那么我们就冒着压制重要和有用的风险。 />
诊断信息。事实上,我们自己只是沉迷,甚至可能是欺骗。第一个例子是无害的,但正好相同的逻辑(获得一个干净的编译)可以引诱我们添加演员实际上隐藏问题,而不是修复它们的



扮演错误隐藏者


这种适得其反的诊断抑制的典型例子是
malloc功能。我相信你知道,malloc的原型是

< stdlib.h> as void * malloc(size_t); - 也就是说,malloc被声明为一个

函数,它将size_t作为参数并返回一个void指针(即

a指向一个类型未知的对象很多年前,在C标准化为ANSI之前,malloc返回了char *,

而不是void *;}。
这是当时最合理的选择,因为

的void类型当然不存在(除了,或许,作为扩展

在某些编译器上)。各种指针类型之间没有隐式转换

,因此有必要将malloc的返回值转换为

所需的指针类型:


#include< stdlib.h>


T * foo(int x)

{

T * new =(T *)malloc(sizeof * new); / *古代历史* /

如果(新)

{

new-> zog = x;

}

返回新的;

}


但是这种情况在1989年不再是真实的 - 这是15年前的一个好消息我写这个。

ANSI C引入了void *指针类型,并赋予它非常有用的

属性,能够表示(不丢失任何信息)任何

对象指针。


因此,不再需要强制转换malloc的返回值。

但这是明智的吗?


显然,如果您的代码必须可以移植到早于1989年ANSI C

标准的编译器,那么您别无选择,只能进行投射。很公平。但是

只有在极少数情况下才会出现这种情况。到目前为止,今天写的大部分C代码都不需要为史前的b
编译器提供服务。因此,在大多数情况下,我们可以忽略添加

演员的原因,并寻找其他优点和缺点。


所有代码都应该做好的东西,或阻止

发生的事情。现在,malloc演员有什么用呢?偶然提出的一个参数是为了保护演员阵容,演员表示指定了返回值的

类型,因此它会生成代码更多

自我记录。但如果这是真的,那么为什么我们不经常使用演员阵容呢?考虑来自K& R2的第12页的示例程序:


#include< stdio.h>


/ * print Fahrenheit-Celsius table

for fahr = 0,20,...,300;浮点版* /

main()

{

浮动fahr,摄氏度;

int lower,鞋帮,步骤;


lower = 0; / *温度下限表* /

上限= 300; / *上限* /

step = 20; / *步长* /


fahr = lower;

while(fahr< = upper){

celsius =( 5.0 / 9.0)*(fahr-32.0);

printf("%3.0f%6.1f \ n",fahr,celsius);

fahr = fahr +步骤;

}

}


现在让我们添加自我记录演员:


#include< stdio.h>


/ *打印华氏度 - 摄氏度表

for fahr = 0,20,...,300;浮点版* /

main()

{

浮动fahr,摄氏度;

int lower, upper,step;


lower =(int)0; / *温度表的下限* /

upper =(int)300; / *上限* /

step =(int)20; / *步长* /


fahr =(浮动)降低;

while((float)fahr< =(int)upper){

摄氏度=(((浮动)

((浮动)5.0 /(浮动)9.0))*

(浮动)((浮动)

(((float)fahr-(float)32.0))));


(int)((int(*)(const char * ,. ..))

printf((const char *)"%3.0f%6.1f \ n",

(float)fahr,(float)摄氏度) );


fahr =(浮动)((浮动)fahr +(浮动)步骤);

}

}


信不信由你,这些演员都是正确的。是的,代码工作

就好了。但突然间,代码不是那么容易阅读,是吗?所以

非常适合自我记录。


好​​吧,好吧 - C ++怎么样?在C ++中,有必要将void *

转换为对象指针类型,因为实现是禁止从

提供隐式转换。

是的,这绝对是真的,但它也完全无关紧要。 C和C ++是非常不同语言的
!它们由通用语法划分。没有人在他们正确的心灵中会梦想说我总是将printf包装在一个名为writeln的
中,以保持与Pascal的兼容性,是吗?但是

因为C和C ++在语法层面上有一些肤浅的相似之处,有些人似乎认为编写用于编译的C代码是必要的。 >
C ++编译器。好吧,它不是。


如果您使用的是C ++编译器,那么无论您是否喜欢它,您都是在写C ++的
代码,而不是C代码。规则不同。如果您希望编写

C ++代码来转换malloc(而不是使用完全可维护的新

分配器,或STL的std :: vector模板),那么那完全取决于你b
;祝你好运,祝你使用C ++一切顺利。这个

的讨论不是针对C ++用户的(除非提醒他们

,他们不是用C语写的,即使他们认为是这样)。 />

如果你想在C ++项目中使用C代码,这很容易做到,没有

投射malloc。使用C编译器编译C代码(duh!),然后使用

链接器将C代码链接到C ++代码。为了这个目的,C ++提供externC

结构。


到目前为止,我们没有找到合适的投射理由。但有什么好的

理由为什么我们不应该演员?是的,有。


首先,正如我之前所说,所有代码应该做好事或停止

发生的事情。 Casting malloc既没有,所以演员已经死了

代码,死代码在C程序中没有位置。


其次,施放malloc实际上可以隐藏一个严重的错误。让我快速说出演员没有造成这个错误的
。但是如果那里有bug,那么演员可以隐藏它的存在。


有问题的错误是无法提供有效的函数原型

for malloc。当然,该函数返回一个void *,但C编译器

并不知道,除非你告诉它。告诉它的最好方法是

#include< stdlib.h>它提供了一个原型,编译器使用它来进行类型检查以及它可以用于代码生成目的。


让我们考虑一对事情可能出错的方式。它们都取决于1989年ANSI C标准第3.3.2.2节的措辞,

如下:

如果括号内的参数列表之前的表达式
函数调用中的
仅包含一个标识符,如果此标识符没有可见的

声明,则标识符为

隐式声明,就像在最里面的块中包含函数调用的
,声明


extern int identifier();


出现。


以下脚注适用于上述文字:

30.即具有外部联动功能没有信息

关于其返回int的参数。实际上它是

没有被定义为具有类型函数返回int,

的行为是未定义的。


虽然脚注不是规范性文本,但它们对于帮助我们理解意图非常有用委员会和合理的实施者将会一般地观察他们,所以我们认真对待他们所说的话非常有意义。


或者,如果您不相信,请考虑标准的3.1.6.2(2),

,其中说:所有引用相同对象或功能的声明

应具有兼容类型;否则行为是未定义的。


从编译器编写器的角度考虑情况。作为他实施的一部分,他提供了一个标准的C库。作为他的C库的一部分,他实现了malloc函数。他几乎肯定使用他自己的C编译器来执行此操作。 C编译器为

malloc生成目标代码,并将此目标代码放入标准C库中,然后发布它的b
。当然,这个目标代码坚定地基于malloc

返回void *。


当你编写一个调用malloc的C程序时,C实现没有
必须编译malloc,因为它已经编译好了。所有它必须做的是

链接标准库(或至少,它实际上是你b $ b使用的部分)到你的程序。所以没有任何改变,就图书馆而言是有价值的。 malloc函数返回void *,就是那个。


在你的程序中,让我们假设您忘记了
#include< stdlib.h>,所以你没有malloc的原型。遇到你的malloc调用时,C编译器,
将遵循ANSI C标准的

3.3.2.2的措辞,并假设malloc返回int。 It

will therefore generate code that assumes the return value of malloc is an

int. But you don’’t assign that value to an object of type int; rather, you

assign it to a pointer!


Under normal circumstances, this would require the compiler to issue a

diagnostic. That’’s because the code would violate a constraint (see

3.3.16.1), and the compiler must issue a diagnostic if the program contains

any constraint violations. But the cast forces the code to satisfy, rather

than violate, the constraint. Consequently, no diagnostic is required.


The wording of the diagnostic is sometimes rather unfortunate. Consider the

wording of the gcc diagnostic for this situation:


initialization makes pointer from integer without a cast


The wording is actually correct, because (by 3.3.2.2) gcc is right to assume

that an undeclared function returns int, and it’’s right in thinking that

you are trying to stick this int value into a pointer, but it’’s a mite

misleading, because it leads you to think that the correct fix is to add a

cast!


With the cast in place, you may not get a diagnostic at all. So what will

happen?


Well, of course, it might just work swimmingly well despite the lack of a

prototype. But we can’’t know that. And even if it does, we have no

guarantee that the same code will also work correctly if we were to switch

to a different compiler.


What sorts of things can go wrong? I offer you two (but by no means the only

two) possibilities. Firstly, what if sizeof(void *) > sizeof(int)? This is

not just a theoretical possibility. It is certainly true for, say, typical

MS-DOS programs using a large memory model. Here’’s how it would break:

malloc returns a void *, but the compiler is required to turn this value

into an int. There aren’’t enough bits in the int to store the whole value,

so some information is lost. The int is then coerced back into a pointer,

but the lost information cannot now be retrieved, and if those lost bits

actually affect the value (say, they weren’’t just a bunch of 0s), then the

effect is that the pointer object receives an incorrect value -- that is,

instead of pointing to the allocated memory block, it points somewhere

completely different instead!


What else could go wrong? Well, consider an implementation which has

separate registers for pointers and integers. On such an implementation,

the library code for malloc will, of course, store the return value, a

pointer, in a pointer register. The compiler, however, doesn’’t know this

(because we didn’’t have a prototype for malloc), so it will actually

collect its return value from an integer register. This is a bit like going

to the wrong Post Office when collecting a parcel, seeing a parcel that

looks about the right size, and grabbing it on the assumption that it’’s the

right one. And yet it can’’t be the right one, because you’’re looking in the

wrong place.


Again, the outcome is that your pointer object does not get the correct

value.


As a consequence, we must conclude that to cast malloc is dangerous, and

that a competent C programmer simply should not do it.


Incidentally, precisely the same argument applies to any function that

returns a pointer; functions such as bsearch, strcpy, memmove, other

standard library functions returning pointers, and of course any of your

own custom functions that return pointers.


Under what circumstances is casting correct?


Very few. Casting is almost always wrong, and the places in which it is

correct are rarely the ones you would guess.


One situation in which casting is a good idea is when you are calling any of

the functions prototyped in <ctype.h>. These functions take an int as

input, but the value stored in that int must either be EOF or a value that

can be represented in an unsigned char. Assuming that you’’re not daft

enough to pass EOF to such a function, then, it makes sense to cast the

value you are passing, unless you have some excellent reason for knowing

that it’’s bound to be in the appropriate range. So, for example, you could

reasonably call toupper in this way:

ch = toupper((unsigned char)ch);


What you don’’t have to do is worry about is casting to int (in this case).

Let the ordinary C promotion mechanism handle that for you.


When you are passing a value to the "tail" of a variadic function, you must

get the type just right, because the normal promotions won’’t be done, which

is in turn because the compiler has no type information to work with. If

the variadic function takes a T *, and you have a void * which you happen

to know points to an object of type T, that’’s fine, but you must cast the

pointer, to yield an expression of type T *. Conversely, if the function

expects a void *, you should cast to void * unless the pointer you have is

already of that type. Thus, when you call printf with a %p format

specifier, your matching pointer either should be a void * already, or

should be cast to one:

printf("Pointer value: %p\n", (void *)MyTPointer);


For the same basic reason, you should cast a size_t when printing it. I

generally use unsigned long for this purpose:

printf("Size: %lu\n", (unsigned long)sizeof MyTObject);


Summary


One of the characteristics of an expert C programmer is that he or she knows

in what circumstances a cast is required and in what circumstances it is at

best redundant and at worst a source of problems. Most programmers,

however, are guilty of "cargo cult" programming where casts are concerned.

Don’’t do that. Be an expert. Know why you are casting, whenever you cast,

and remember when maintaining your own or other people’’s code that almost

all casts in existing code should not actually be there.


----------------------------------------------------------------------

The full text of this article can be found on my Web site, at:


<http://www.cpax.org.uk/prg/writings/casting.php>


--

Richard Heathfield

"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk

电子邮件:rjh在上面的域名(但显然放弃了www)



Here''s an explanation for you:

----------------------------------------------------------------------

Casting

Implicit conversions

In the C programming language, there are two kinds of conversions between
expressions of different types. The first is supplied by the compiler
itself. This is known as an implicit conversion. Here''s an example of its
use:

long int foo = 314159265L;
double bar = foo;

This kind of conversion is, of course, very natural. In fact, an example of
such a conversion occurs as early as page 12 of K&R2 (where the conversion
is from float to double). Such conversions are woven into the very fabric
of the language, and are so common and natural that we often fail to notice
them.

Explicit conversions (casts)

There is, however, another way to convert an expression from one type into
another; this second method is known as an explicit conversion, or cast.
Here''s an example of a cast:

IsLowerCase = islower((unsigned char)*p);

This cast is a good one, by the way. There are circumstances in which
explicit conversions, or casts, are a convenience which allows us to write
better, cleaner code than would otherwise be the case. And yet casts are
poorly understood.

For some reason, casting is very popular among C programmers. It''s as if a
cast is a magic wand, that can magically transform one type into another,
irrespective of semantics, logic, or common sense. In fact, there is very
little (if any) sense in casting an expression for which a perfectly
adequate implicit conversion already exists. There are very few exceptions
to this rule of thumb. For example, consider this code:

#include <math.h>
long GetHypotenuse(long height, long base)
{
return sqrt(height * height + base * base);
}

Some compilers will complain about this code, arguing that sqrt returns a
double, and that assigning such a value to a long can result in a loss of
information. Well, that''s true. But it''s also true that, if such a loss of
information is intended, then there''s no problem (because we''re only
interested in the integer part of the result); and if such a loss of
information is not intended, then we really ought to pay attention to the
compiler''s complaint.

Casts as diagnostic suppressors

We can often suppress the warning by using a cast:

#include <math.h>
long GetHypotenuse(long height, long base)
{
return (long)sqrt(height * height + base * base);
}

The cast, in effect, tells the compiler: "I know what I''m doing! So shut up
already!" Many C programmers do this (even those who only think that they
know what they''re doing). But is the cast justified? Well, in this case,
there is a (perhaps spurious) justification, not in technical terms but
purely in terms of getting a clean compilation. Alas, this excuse is used
to justify a great many unnecessary casts. Yes, it''s true that a nice clean
compilation is good to see. But if we achieve that state only by gagging
the compiler, without understanding the possible implications of such
gagging, then we are running the risk of suppressing important and useful
diagnostic information. In fact, we are merely indulging, and maybe even
deceiving, ourselves. That first example is innocuous enough, but precisely
the same logic (getting a clean compilation) can lure us into adding casts
that actually hide problems, instead of fixing them.

Casts as bug-hiders

The canonical example of this counter-productive diagnostic suppression is
the malloc function. As I''m sure you know, malloc is prototyped in
<stdlib.h> as void *malloc(size_t); -- that is, malloc is declared to be a
function taking a size_t as a parameter and returning a void pointer (i.e.
a pointer to an object whose type is not known).

Many years ago, before C was standardised by ANSI, malloc returned char *,
rather than void *; this was the most rational choice at the time, because
the void type didn''t actually exist then (except, perhaps, as an extension
on some compilers). No implicit conversions between various pointer types
were supplied, so it was necessary to cast the return value of malloc into
the pointer type that you required:

#include <stdlib.h>

T *foo(int x)
{
T *new = (T *)malloc(sizeof *new); /* ancient history */
if(new)
{
new->zog = x;
}
return new;
}

But this ceased to be true in 1989 -- a good 15 years ago as I write this.
ANSI C introduced the void * pointer type, and gave it the very useful
property of being able to represent (without loss of information) any
object pointer whatsoever.

Consequently, it is no longer necessary to cast the return value of malloc.
But is it wise?

Clearly, if your code must be portable to compilers that pre-date the ANSI C
Standard of 1989, then you have no choice but to cast. Fair enough. But
this is true only in a vanishingly small number of cases. By far the
majority of C code written today does not need to cater for prehistoric
compilers. So we can, for the most part, ignore that reason for adding the
cast, and look for other advantages and disadvantages.

All code should either do something good, or stop something bad from
happening. Now, what good does a malloc cast do? One argument that is
occasionally raised in defence of the cast is that "the cast indicates the
type to which the return value is being assigned, so it makes the code more
self-documenting". But if that is true, then why do we not use casts more
often? Consider this example program from K&R2, page 12:

#include <stdio.h>

/* print Fahrenheit-Celsius table
for fahr = 0, 20, ..., 300; floating-point version */
main()
{
float fahr, celsius;
int lower, upper, step;

lower = 0; /* lower limit of temperature table */
upper = 300; /* upper limit */
step = 20; /* step size */

fahr = lower;
while(fahr <= upper) {
celsius = (5.0/9.0) * (fahr-32.0);
printf("%3.0f %6.1f\n", fahr, celsius);
fahr = fahr + step;
}
}

Now let''s add those "self-documenting" casts:

#include <stdio.h>

/* print Fahrenheit-Celsius table
for fahr = 0, 20, ..., 300; floating-point version */
main()
{
float fahr, celsius;
int lower, upper, step;

lower = (int)0; /* lower limit of temperature table */
upper = (int)300; /* upper limit */
step = (int)20; /* step size */

fahr = (float)lower;
while((float)fahr <= (int)upper) {
celsius = (((float)
((float)5.0/(float)9.0)) *
(float)((float)
(((float)fahr-(float)32.0))));

(int)((int (*)(const char *, ...))
printf((const char *)"%3.0f %6.1f\n",
(float)fahr, (float)celsius));

fahr = (float)((float)fahr + (float)step);
}
}

Believe it or not, those casts are all "correct". And yes, the code works
just fine. But suddenly the code isn''t quite as easy to read, is it? So
much for self-documentation.

Well, all right -- what about C++? In C++, it is necessary to cast void *
into an object pointer type, because the implementation is forbidden from
providing an implicit conversion.

Yes, that''s absolutely true, but it''s also utterly irrelevant. C and C++ are
very different languages! They are divided by a common syntax. Nobody in
their right mind would dream of saying "I always wrap printf in a function
named writeln, to maintain compatibility with Pascal", would they? But
because C and C++ have superficial similarities at the syntax level, some
people seem to think it''s necessary to write C code that compiles with a
C++ compiler. Well, it isn''t.

If you are using a C++ compiler, then whether you like it or not, you''re
writing C++ code, not C code. The rules are different. If you wish to write
C++ code that casts malloc (instead of using the perfectly serviceable new
allocator, or the STL''s std::vector template), then that''s entirely up to
you; good luck to you, and I wish you all joy in your use of C++. This
discussion is not directed at C++ users (except, perhaps, to remind them
that they are not writing in C, even if they think they are).

If you wish to use C code in a C++ project, that''s easy to do, without
casting malloc. Use a C compiler to compile the C code (duh!), and then use
a linker to link the C code to the C++ code. C++ supplies the extern "C"
construct for precisely this purpose.

So far, we have found no good reasons for casting. But are there any good
reasons why we should not cast? Yes, there are.

Firstly, as I said earlier, all code should either do something good or stop
something bad happening. Casting malloc does neither, so the cast is dead
code, and dead code has no place in a C program.

Secondly, casting malloc can actually hide a serious bug. Let me say quickly
that the cast doesn''t cause the bug. But if the bug is there, the cast can
conceal its presence.

The bug in question is that of failing to provide a valid function prototype
for malloc. The function returns a void *, of course, but the C compiler
doesn''t know that, unless you tell it. The best way to tell it is to
#include <stdlib.h> which provides a prototype which the compiler uses to
do type-checking and which it can exploit for code generation purposes.

Let''s consider a couple of ways in which things can go wrong. They both
hinge on the wording of section 3.3.2.2 of the ANSI C Standard of 1989,
which is as follows:
If the expression that precedes the parenthesized argument list
in a function call consists solely of an identifier, and if no
declaration is visible for this identifier, the identifier is
implicitly declared exactly as if, in the innermost block
containing the function call, the declaration

extern int identifier();

appeared.

The following footnote applies to the above text:
30. That is, a function with external linkage and no information
about its parameters that returns an int. If in fact it is
not defined as having type "function returning int ," the
behavior is undefined.

Whilst footnotes are not normative text, they are useful in helping us to
understand the intent of the committee, and sensible implementors will
generally observe them, so it makes sense for us to take what they say very
seriously.

Or, if you''re not convinced by that, consider 3.1.6.2(2) of the Standard,
which says: "All declarations that refer to the same object or function
shall have compatible type; otherwise the behavior is undefined."

Consider the situation from the point of view of the compiler writer. As
part of his implementation, he provides a standard C library. As part of
his C library, he implements the malloc function. He almost certainly uses
his own C compiler to do this. The C compiler generates object code for
malloc, and this object code is placed into the standard C library, which
he then releases. Of course, this object code is based firmly on a malloc
that returns void *.

When you write a C program that calls malloc, the C implementation doesn''t
have to compile malloc, because it is already compiled. All it has to do is
link the standard library (or at least, the parts of it that you actually
use) to your program. So nothing has changed, as far as the library is
concerned. The malloc function returns void *, and that''s that.

In your program, let''s just hypothesise for a moment that you forgot to
#include <stdlib.h>, so you have no prototype for malloc. The C compiler,
on encountering your malloc call, will therefore follow the wording of
3.3.2.2 of the ANSI C Standard, and presume that malloc returns int. It
will therefore generate code that assumes the return value of malloc is an
int. But you don''t assign that value to an object of type int; rather, you
assign it to a pointer!

Under normal circumstances, this would require the compiler to issue a
diagnostic. That''s because the code would violate a constraint (see
3.3.16.1), and the compiler must issue a diagnostic if the program contains
any constraint violations. But the cast forces the code to satisfy, rather
than violate, the constraint. Consequently, no diagnostic is required.

The wording of the diagnostic is sometimes rather unfortunate. Consider the
wording of the gcc diagnostic for this situation:

initialization makes pointer from integer without a cast

The wording is actually correct, because (by 3.3.2.2) gcc is right to assume
that an undeclared function returns int, and it''s right in thinking that
you are trying to stick this int value into a pointer, but it''s a mite
misleading, because it leads you to think that the correct fix is to add a
cast!

With the cast in place, you may not get a diagnostic at all. So what will
happen?

Well, of course, it might just work swimmingly well despite the lack of a
prototype. But we can''t know that. And even if it does, we have no
guarantee that the same code will also work correctly if we were to switch
to a different compiler.

What sorts of things can go wrong? I offer you two (but by no means the only
two) possibilities. Firstly, what if sizeof(void *) > sizeof(int)? This is
not just a theoretical possibility. It is certainly true for, say, typical
MS-DOS programs using a large memory model. Here''s how it would break:
malloc returns a void *, but the compiler is required to turn this value
into an int. There aren''t enough bits in the int to store the whole value,
so some information is lost. The int is then coerced back into a pointer,
but the lost information cannot now be retrieved, and if those lost bits
actually affect the value (say, they weren''t just a bunch of 0s), then the
effect is that the pointer object receives an incorrect value -- that is,
instead of pointing to the allocated memory block, it points somewhere
completely different instead!

What else could go wrong? Well, consider an implementation which has
separate registers for pointers and integers. On such an implementation,
the library code for malloc will, of course, store the return value, a
pointer, in a pointer register. The compiler, however, doesn''t know this
(because we didn''t have a prototype for malloc), so it will actually
collect its return value from an integer register. This is a bit like going
to the wrong Post Office when collecting a parcel, seeing a parcel that
looks about the right size, and grabbing it on the assumption that it''s the
right one. And yet it can''t be the right one, because you''re looking in the
wrong place.

Again, the outcome is that your pointer object does not get the correct
value.

As a consequence, we must conclude that to cast malloc is dangerous, and
that a competent C programmer simply should not do it.

Incidentally, precisely the same argument applies to any function that
returns a pointer; functions such as bsearch, strcpy, memmove, other
standard library functions returning pointers, and of course any of your
own custom functions that return pointers.

Under what circumstances is casting correct?

Very few. Casting is almost always wrong, and the places in which it is
correct are rarely the ones you would guess.

One situation in which casting is a good idea is when you are calling any of
the functions prototyped in <ctype.h>. These functions take an int as
input, but the value stored in that int must either be EOF or a value that
can be represented in an unsigned char. Assuming that you''re not daft
enough to pass EOF to such a function, then, it makes sense to cast the
value you are passing, unless you have some excellent reason for knowing
that it''s bound to be in the appropriate range. So, for example, you could
reasonably call toupper in this way:
ch = toupper((unsigned char)ch);

What you don''t have to do is worry about is casting to int (in this case).
Let the ordinary C promotion mechanism handle that for you.

When you are passing a value to the "tail" of a variadic function, you must
get the type just right, because the normal promotions won''t be done, which
is in turn because the compiler has no type information to work with. If
the variadic function takes a T *, and you have a void * which you happen
to know points to an object of type T, that''s fine, but you must cast the
pointer, to yield an expression of type T *. Conversely, if the function
expects a void *, you should cast to void * unless the pointer you have is
already of that type. Thus, when you call printf with a %p format
specifier, your matching pointer either should be a void * already, or
should be cast to one:
printf("Pointer value: %p\n", (void *)MyTPointer);

For the same basic reason, you should cast a size_t when printing it. I
generally use unsigned long for this purpose:
printf("Size: %lu\n", (unsigned long)sizeof MyTObject);

Summary

One of the characteristics of an expert C programmer is that he or she knows
in what circumstances a cast is required and in what circumstances it is at
best redundant and at worst a source of problems. Most programmers,
however, are guilty of "cargo cult" programming where casts are concerned.
Don''t do that. Be an expert. Know why you are casting, whenever you cast,
and remember when maintaining your own or other people''s code that almost
all casts in existing code should not actually be there.

----------------------------------------------------------------------
The full text of this article can be found on my Web site, at:

<http://www.cpax.org.uk/prg/writings/casting.php>

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)


这篇关于memcpy和指针/数组混淆的问题 - 再次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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