指针的强制类型转换,到底怎么回事?

ssduer 2009-11-08 09:09:06
这样一段:
#include<stdio.h>
#include<stdlib.h>
int memorycpy(void *dst,void *src,size_t n)
{
size_t k;
size_t i;
if(n>=8){
k=n;
k>>=3;
for(i=0;i<k;i++)
*((long long*)dst++)=*((long long*)src++);
n-=8*k;
}
if(n>=4){
k=n;
k>>=2;
*((long*)dst++)=*((long*)src++);
n-=4*k;
}
if(n>=2){
k=n;
k>>=1;
*((short*)dst++)=*((short*)src++);
n-=2*k;
}
if(n>=1){
k=n;
*((char*)dst++)=*((char*)src++);
}
}
int main()
{
char* src="1234567890";
char* dst=(char*)malloc(11);
memorycpy(dst,src,sizeof(src));
printf("%s\n",dst);
return 0;
}

上面标红色的四句到底能不能实现将dst和src先转换类型,再以新的类型自增1?这里语法应该写成什么样子?
在gcc里编译能通过,但是运行结果不对,只打印出1234。当src小于四字节是相应能打印出1、2、3、4字节,但是src再大还是只打印出1234。
而且,我拿到vc中编译根本通不过,红色的几行error C2036: 'void *' : unknown size,这样肯定不符合C的语法,但是应该怎么写呢?求助各位大虾帮忙,菜鸟感激不尽!
...全文
594 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
www_adintr_com 2009-11-10
  • 打赏
  • 举报
回复
在 C 中不需要引用,直接像 *(((long*)dst)++)=*(((long*)src)++) 就可以通过了.
我在 VC2005 下面,如果扩展名为 .cpp 则需要引用才能编译通过,如果扩展名为 C, 则加引用出错,去掉引用通过.

对于循环像你那样确实是可以的.
ssduer 2009-11-10
  • 打赏
  • 举报
回复
强烈感谢楼上指教。让我明白了c++中的引用,而且我在c++中调试也成功了,非常感谢!
可是,我要写的是纯c的实现,c里面没有引用一说啊~~只用c这里还能实现吗?
另外,经过测试,visual studio中确实支持long long 类型,但是我的Vc6 不行,再就是您说的第4和5,我在复制8字节时使用了循环,而不足8字节时4、2、1之多有一个,对吧。

希望能有熟悉C的牛人帮我看这里只用参数能实现吗?
谢谢。
WOBUGUAN 2009-11-10
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 ssduer 的回复:]
首先感谢楼上的热心,您的代码我原来也是这么写的,但是好像这样即时使用即时声明变量好像不符合C的语法吧(虽然可能编译能通过),C89不允许这样吧,好像?

我希望的是只使用传入参数后的形参dst和src的移动来实现我的目的,但是还没找到一种好的方法。而且,现在的问题是为什么这样写 *((char*)dst++)=*((char*)src++); 在gcc中编译能通过,而在vc中不行呢??这到底符不符合语法?只依靠dst与src能实现吗?

谢谢!
[/Quote]

即时使用即时声明变量的确不符合C语言的语法,所以我的代码多加了一对大括号。
你这样写*((char*)dst++)=*((char*)src++)的话会先自增然后才强制转换,而且void*指针自增是不符合语法的。GCC编译会给警告。
转型为指针的引用是微软编译器的扩展,只能在C++文件中使用。标准对这点是含糊的。标准说转型为引用是可以产生左值的,但是标准又说引用必须是有名字的。可以用typedef造出名字。
微软编译器对C文件允许直接转型成左值,所以*(((long*)dst)++)=*(((long*)src)++)就可以了。这是不符合C标准或C++标准的,标准不允许转型产生左值。
long long 类型是符合C99标准的。sizeof比直接用常数好。
这样的写法应该是严格符合标准的:*(*(long **)&dst)++ = *(*(long **)&src)++;

rabbitlzx 2009-11-10
  • 打赏
  • 举报
回复
为什么非要把语句写这么长 这么复杂,多写几行不好么?!
www_adintr_com 2009-11-09
  • 打赏
  • 举报
回复
另外,上面对 memorycpy 函数而言,并不能确定 src 和 dst 指针就是四字节对齐的,如果不是四字节对齐的时候,效率也不能保证。
www_adintr_com 2009-11-09
  • 打赏
  • 举报
回复

#include <stdio.h>
#include <stdlib.h>
int memorycpy(void *dst,void *src,size_t n)
{
while(n > 0)
{
if(n>=sizeof(long long)){
*(((long long*&)dst)++)=*(((long long*&)src)++);
n-=sizeof(long long);
}
if(n>=4){
*(((long*&)dst)++)=*(((long*&)src)++);
n-=4;
}
if(n>=sizeof(short)){
*(((short*&)dst)++)=*(((short*&)src)++);
n-=sizeof(short);
}
if(n>=sizeof(char)){
*(((char*&)dst)++)=*(((char*&)src)++);
n -= sizeof(char);
}
}

return 0;
}
int main()
{
char* src="1234567890";
char* dst=(char*)malloc(11);
memorycpy(dst,src,strlen(src) + 1);
printf("%s\n",dst);
return 0;
}


1. 转型为指针的引用就是左值可以自加了,不会 error C2105: '++' needs l-value
2. VC 也是有 long long 类型的.
3. 各种类型的长度在不同环境下是不同的,尽量使用 sizeof 来获得大小而不是直接写常数。
4. 没有循环是处理不完字符串的,必须加一个 while 循环。
5. k=n; k>>=3; for(i=0;i <k;i++) 不用了,转成 long long 类型后一次就可以拷贝 8 个字节了。
6. sizeof(src) 得到的是指针的大小 4, 要得到字符串的大小得用 strlen 才行。
do_fork 2009-11-08
  • 打赏
  • 举报
回复
gcc可以编译,hoho
jernymy 2009-11-08
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 slowgrace 的回复:]
*((long long*)dst++)=*((long long*)src++);

这句话我觉得语法不对。在VC6里编译也通不过。
[/Quote]

是啊,vc6.0的编译不过,而且楼主的这几个地方也要改一下了

*(((long*)dst)++)=*(((long*)src)++);
*(((short*)dst)++)=*(((short*)src)++);
*(((char*)dst)++)=*(((char*)src)++);

否则也是编译不通过了
slowgrace 2009-11-08
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 ssduer 的回复:]
那么写成这样((char*)dst)++行不行啊?
[/Quote]

这样可以。
slowgrace 2009-11-08
  • 打赏
  • 举报
回复
*((long long*)dst++)=*((long long*)src++);

这句话我觉得语法不对。在VC6里编译也通不过。
www_adintr_com 2009-11-08
  • 打赏
  • 举报
回复
可以
ssduer 2009-11-08
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 wobuguan 的回复:]
不好意思,没看题就乱叫了。
你可以把这个循环
for(i=0;i <k;i++)
    *((long long*)dst++)=*((long long*)src++);
改成这样,就可以自增了。
{
    long long *dstdup = dst, *srcdup = src;
    for(i=0;i <k;i++)
        *dstdup++=*srcdup++;
    dst = dstdup;
    src = srcdup;
}
[/Quote]

首先感谢楼上的热心,您的代码我原来也是这么写的,但是好像这样即时使用即时声明变量好像不符合C的语法吧(虽然可能编译能通过),C89不允许这样吧,好像?

我希望的是只使用传入参数后的形参dst和src的移动来实现我的目的,但是还没找到一种好的方法。而且,现在的问题是为什么这样写 *((char*)dst++)=*((char*)src++); 在gcc中编译能通过,而在vc中不行呢??这到底符不符合语法?只依靠dst与src能实现吗?

谢谢!
ssduer 2009-11-08
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 adlay 的回复:]
自增操作符的优先级大于转型操作符
[/Quote]
那么写成这样((char*)dst)++行不行啊?
www_adintr_com 2009-11-08
  • 打赏
  • 举报
回复
自增操作符的优先级大于转型操作符
WOBUGUAN 2009-11-08
  • 打赏
  • 举报
回复
不好意思,没看题就乱叫了。
你可以把这个循环
for(i=0;i <k;i++)
*((long long*)dst++)=*((long long*)src++);
改成这样,就可以自增了。
{
long long *dstdup = dst, *srcdup = src;
for(i=0;i <k;i++)
*dstdup++=*srcdup++;
dst = dstdup;
src = srcdup;
}
WOBUGUAN 2009-11-08
  • 打赏
  • 举报
回复
void*指针怎么能自增?
ssduer 2009-11-08
  • 打赏
  • 举报
回复
各位老大说话负责人点,long long 类型gcc里面有,而相应的64位类型在VC中是__int64 ,拿到vc编译当然通不过!
还有,类似((long *)dst)++;在VC中报错:error C2105: '++' needs l-value,各位神人到底是没试过就回答?
那个在gcc中可以,问题是我在主函数中传入参数写 的是sizeof(src),当然四字节,输出1234……
求大家好好给看看啊~~

69,369

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧