谁能帮我写C的程序,怎么调试程序硬件啊

谁能帮我写一个c语言的程序,感谢啊!我会非常感谢的!_百度知道
谁能帮我写一个c语言的程序,感谢啊!我会非常感谢的!
j;n-2;n&j++)printf(&quot,d;n+=d*d*d;);\);for(i=0;for(i=100;i++)printf(&n-2;for(j=0;*&do{d=m%10;i&n&10;if(i==n){printf(&n&}void shuixian(){i&i&i&n;&#92,n);*\i++){int m=i;printf(&*&i++)printf(&*&);n;i++){printf(&m=m/ &printf(&printf(&;}for(i=0;999;);for(i=0;);n&%d\);j&}while(m);),n=0void print(int n){int i
知道智能回答机器人
我是知道站内的人工智能,可高效智能地为您解答问题。很高兴为您服务。
其他类似问题
为您推荐:
其他1条回答
voidswap(),int*qs2),int*q2;改成voidexchange(int*q1;改成voidswap(int*qs1,int*q3)voidexchange()
c语言的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁C 语言调试器是如何工作的? - 文章 - 伯乐在线
& C 语言调试器是如何工作的?
当你用 GDB 的时候,可以看到它完全控制了应用程序进程。当你在程序运行的时候用 Ctrl + C,程序的运行就能够终止,而GDB能展示它的当前地址、堆栈跟踪信息之类的内容。
但是它是怎么办到的呢?
但是它们怎么不工作呢?
开始,让我们先研究它怎样才会不工作。它不能通过阅读和分析程序的二进制信息来模拟程序的运行。它其实能做,而那应该能起作用(Valgrind 内存调试器就是这样工作的),但是这样的话会很慢。Valgrind会让程序慢1000倍,但是GDB不会。它的工作机制与Qemu虚拟机一样。
所以到底是怎么回事?黑魔法?……不,如果那样的话就太简单了。
另一种猜想?……?破解!是的,这里正是这样的。操作系统内核也提供了一些帮助。
首先,关于Linux的进程机制需要了解一件事:父进程可以获得子进程的附加信息,也能够ptrace它们。并且你可以猜到的是,调试器是被调试的进程的父进程(或者它会变成父进程,在Linux中进程可以将一个进程变为自己子进程:-))
Linux Ptrace API
Linux Ptrace API 允许一个(调试器)进程来获取低等级的其他(被调试的)进程的信息。特别的,这个调试器可以:
读写被调试进程的内存 :PTRACE_PEEKTEXT、PTRACE_PEEKUSER、PTRACE_POKE……
读写被调试进程的CPU寄存器 PTRACE_GETREGSET、PTRACE_SETREGS
因系统活动而被提醒:PTRACE_O_TRACEEXEC, PTRACE_O_TRACECLONE, PTRACE_O_EXITKILL, PTRACE_SYSCALL(你可以通过这些标识区分exec syscall、clone、exit以及其他系统调用)
控制它的执行:PTRACE_SINGLESTEP、PTRACE_KILL、PTRACE_INTERRUPT、PTRACE_CONT (注意,CPU在这里是单步执行)
修改它的信号处理:PTRACE_GETSIGINFO、PTRACE_SETSIGINFO
Ptrace是如何实现的?
Ptrace的实现不在本文讨论的范围内,所以我不想进一步讨论,只是简单地解释它是如何工作的(我不是内核专家,如果我说错了请一定指出来,并原谅我过分简化:-))
Ptrace ,所以它能够获取进程所有内核级信息:
读写数据?Linux有。
获取CPU寄存器?用很轻松(这里没有什么复杂的,因为CPU寄存器在进程未被调度时保存在Linux的struct task_struct *调度结构中)。
修改信号处理?更新域
单步执行?在处理器出发执行前,设置进程task结构的right flag(、)
Ptrace是在很多计划的操作中被Hooked(搜索函数),所以它可以在被询问时(PTRACE_O_TRACEEXEC选项和与它相关的),向调试器发出一个。
没有Ptrace的系统会怎么样呢?
这个解释超出了特定的Linux本地调试,但是对于大部分其他环境是合理的。要了解GDB在不同目标平台请求的内容,你可以看一下它在里面的操作。
在这个目标接口里,你可以看到所有C调试需要的高级操作:
struct target_ops
struct target_ops *
/* To the target under this one.
const char *to_ /* Name this target type */
const char *to_
/* Name for printing */
const char *to_
/* Documentation.
Does not include trailing
newline, and starts with a one-line descrip-
tion (probably similar to to_longname).
void (*to_attach) (struct target_ops *ops, const char *, int);
void (*to_fetch_registers) (struct target_ops *, struct regcache *, int);
void (*to_store_registers) (struct target_ops *, struct regcache *, int);
int (*to_insert_breakpoint) (struct target_ops *, struct gdbarch *,
struct bp_target_info *);
int (*to_insert_watchpoint) (struct target_ops *,
CORE_ADDR, int, int, struct expression *);
123456789101112131415161718
struct target_ops {&&struct target_ops *beneath;&& /* To the target under this one.&&*/&&const char *to_shortname; /* Name this target type */&&const char *to_longname;&&/* Name for printing */&&const char *to_doc;&&&&&& /* Documentation.&&Does not include trailing&&&&&&&&&&&&&& newline, and starts with a one-line descrip-&&&&&&&&&&&&&& tion (probably similar to to_longname).&&*/& void (*to_attach) (struct target_ops *ops, const char *, int); void (*to_fetch_registers) (struct target_ops *, struct regcache *, int); void (*to_store_registers) (struct target_ops *, struct regcache *, int); int (*to_insert_breakpoint) (struct target_ops *, struct gdbarch *,&&&&&&&&&&&& struct bp_target_info *); int (*to_insert_watchpoint) (struct target_ops *,&&&&&&&&&&&& CORE_ADDR, int, int, struct expression *); ...}
普通的GDB调用这些函数,然后目标相关的组件再实现它们。(概念上)这是一个栈,或者一个金字塔:栈顶的是非常通用的,比如:
系统特定的
本地或调试
调试方式特定的(、)
指令集特定的(Linux 、Linux )
那个目标很有趣,因为它通过一个连接协议(TCP/IP、串行端口)把两台“电脑”间的执行栈分离开来。
那个远程的部分可以是运行在另一台Linux机器上的gdbserver。但是它也可以是一个硬件调试端口的界面(JTAG) 或者一个虚拟的机器管理程序(比如 ),并能够代替内核和ptrace的功能。那个远程根调试器会查询管理程序的结构,或者直接地查询处理器硬件寄存器来代替对OS内核结构的查询。
想要深层次学习这个远程协议,Embecosm 写了一篇。Gdbserver的事件处理循环在,而也可以在这里找到。
我们能看到ptrace的API提供了这里所有底层机制被要求实现的调试器:
获取exec系统调用并从调用的地方阻止它执行
查询CPU的寄存器来获得处理器当前指令以及栈的地址
获取clone或fork事件来检测新线程
查看并改变数据地址读取并改变内存的变量
但是这就是一个调试器的全部工作吗?不,这只是那些非常低级的部分……它还会处理符号。这是,链接源程序和二进制文件。被忽视可能也是最重要的的一件事:断点!我会首先解释一下断点是如何工作的,因为这部分内容非常有趣且需要技巧,然后回到符号处理。
断点不是Ptrace API的一部分
就像我们之前看到的那样,断点不是ptrace API的一部分。但是我们可以改动内存并获取被调试的程序信号。你看不到其中的相关之处?这是因为断点的实现比较需要技巧并且还要一点hack!让我们来检验一下如何在一个指定的地址设置一个断点。
1、这个调试器读取(ptrace追踪)存在地址里的二进制指令,并保存在它自己的数据结构中。
2、它在这个位置写入一个不合法的指令。不管这个指令是啥,只要它是不合法的。
3、当被调试的程序运行到这个不合法的指令时(或者更准确地说,处理器将内存中的内容设置好时)它不会继续运行(因为它是不合法的)。
4、在现代多任务系统中,一个不合法的指令不会使整个系统崩溃掉,但是会通过引发一个中断(或错误)把控制权交回给系统内核。
5、这个中断被Linux翻译成一个SIGTRAP信号,然后被发送到处理器……或者发给它的父进程,就像调试器希望的那样。
6、调试器获得信号并查看被调试的程序指令指针的值(换言之,是陷入 trap发生的地方)。如果这个IP地址是在断点列表中,那么就是一个调试器的断点(否则就是一个进程中的错误,只需要传过信号并让它崩溃)。
7、现在,那个被调试的程序已经停在了断点,调试器可以让用户来做任何他/她想要做的事,等待时机合适继续执行。
8、为了要继续执行,这个调试器需要 1、写入正确的指令来回到被调试的程序的内存; 2、单步执行(继续执行单个CPU指令,伴随着ptrace 单步执行); 3、把非法指令写回去(使得这个执行过程下一次可以再次停止) ;4、让这个执行正常运行
很整洁,是不是?作为一个旁观的评论,你可以注意到,如果不是所有线程同时停止的话这个算法是不会工作的(因为运行的线程可能会在合法的指令出现时传出断点)。我不会详细讨论GDB是如何解决这个问题的,但在这篇论文里已经说得很详细了:。简要地说,他们把指令写到内存中的其他地方,然后把那个指令的指针指向那个地址并单步执行处理器。但是问题在于一些指令是和地址相关的,比如跳转和条件跳转……
处理符号和调试信息
现在,让我们回到信号和调试信息处理。我没有详细地学习这部分,所以只是大体地说一说。
首先,我们是否可以不使用调试信息和信号地址来调试呢?答案是可以。因为正如我们看到过的那样,所有的低级指令是对CPU寄存器和内存地址来操作的,不是源程序层面的信息。因此,这个到源程序的链接只是为了方便用户。没有调试信息的时候,你看程序的方式就像是处理器(和内核)看到的一样:二进制(汇编)指令和内存字节。GDB不需要进一步的信息来把二进制信息翻译成CPU指令:
(gdb) x/10x $pc # heXadecimal representation
0xxx55f43fd89
0x03a8ec81
0x8bx8b48643e
(gdb) x/10i $pc # Instruction representation
=& 0x402c60:
$0x3a8,%rsp
(%rsi),%rdi
123456789101112131415
(gdb) x/10x $pc # heXadecimal representation0x402c60:&& 0x&&0x&&0x55f48949&&0x4853fd890x402c70:&& 0x03a8ec81&&0x8b480000&&0x8b48643e&&0x0x402c80:&& 0x&&0x(gdb) x/10i $pc # Instruction representation=> 0x402c60:&&&&push&& %r150x402c62:&& push&& %r140x402c64:&& push&& %r130x402c66:&& push&& %r120x402c68:&& mov&&&&%rsi,%r120x402c6b:&& push&& %rbp0x402c6c:&& mov&&&&%edi,%ebp0x402c6e:&& push&& %rbx0x402c6f:&& sub&&&&$0x3a8,%rsp0x402c76:&& mov&&&&(%rsi),%rdi
现在,如果我们加上调试信息,GDB能够把符号名称和地址配对:
$1 = (void (*)()) 0x402c60 &main&
(gdb) $pc$1 = (void (*)()) 0x402c60 <main>
你可以通过 nm -a $file 来获取ELF二进制的符号列表:
nm -a /usr/lib/debug/usr/bin/ls.debug | grep & main&
2c60 T main
nm -a /usr/lib/debug/usr/bin/ls.debug | grep " main"2c60 T main
GDB还会能够展示堆栈跟踪信息(稍后会详细说),但是只有感兴趣的那部分:
(gdb) where
0x769e3 in _IO_new_file_write ()
0x77e4c in new_do_write ()
_IO_new_do_write ()
0x78223 in _IO_new_file_overflow ()
0x85bb in print_current_files ()
0x431b in main ()
(gdb) where#0&&write ()#1&&0x769e3 in _IO_new_file_write ()#2&&0x77e4c in new_do_write ()#3&&_IO_new_do_write ()#4&&0x78223 in _IO_new_file_overflow ()#5&&0x85bb in print_current_files ()#6&&0x431b in main ()
我们现在有了PC地址和相应的函数,就是这样。在一个函数中,你将需要对着汇编来调试!
现在让我们加入调试信息:就是DWARF规范下的gcc -g选项。我不是特别熟悉这个规范,但我知道它提供的:
地址到代码行和行到地址的配对
数据类型的定义,包括typedef和structure
本地变量和函数参数以及它们的类型
$ dwarfdump /usr/lib/debug/usr/bin/ls.debug | grep 402ce4
0x00402ce4
[1289, 0] NS
$ addr2line -e /usr/lib/debug/usr/bin/ls.debug
0x00402ce4
/usr/src/debug/coreutils-8.21/src/ls.c:1289
$ dwarfdump /usr/lib/debug/usr/bin/ls.debug | grep 402ce40x00402ce4&&[1289, 0] NS$ addr2line -e /usr/lib/debug/usr/bin/ls.debug&&0x00402ce4/usr/src/debug/coreutils-8.21/src/ls.c:1289
试一试dwarfdump来查看二进制文件里嵌入的信息。addr2line也能用到这些信息:
很多源代码层的调试命令会依赖于这些信息,比如next命令,这会在下一行的地址设置一个断点,那个print命令会依赖于变量的类型来输出(char、int、float,而不是二进制或十六进制)。
我们已经见过调试器内部的好多方面了,所以我只会最后说几点:
这个堆栈跟踪信息也是通过当前的帧是向上“解开(unwinded)”的($sp和$bp/#fp),每个堆栈帧处理一次。函数的名称和参数以及本地变量名可以在调试信息中找到。
监视点(&code&watchpoints)是通过处理器的帮助(如果有)实现的:在寄存器里标记哪些地址应该被监控,然后它会在那内存被读写的时候引发一个异常。如果不支持这项功能,或者你请求的断点超过了处理器所支持的……那么调试器就会回到“手动”监视:一个指令一个指令地执行这个程序,并检查是否当前的操作到达了一个监视点的地址。是的,这很慢!
反向调试也可以这样进行,记录每个操作的效果,并反向执行。
条件断点是正常的断点,除非在内部,调试器在将控制权交给用户前检查当前的情况。如果当前的情况不满足,程序将会默默地继续运行。
还可以玩gdb gdb,或者更好的(好多了)gdb --pid $(pid of gdb),因为把两个调试器放到同一个终端里是疯狂的:-)。还可以调试系统:
qemu-system-i386 -gdb tcp::1234
gdb --pid $(pidof qemu-system-i386)
gdb /boot/vmlinuz --exec &target remote localhost:1234&
qemu-system-i386 -gdb tcp::1234gdb --pid $(pidof qemu-system-i386)gdb /boot/vmlinuz --exec "target remote localhost:1234"
但我会在另一篇文章里提到!
关于作者:
可能感兴趣的话题
关于伯乐在线博客
在这个信息爆炸的时代,人们已然被大量、快速并且简短的信息所包围。然而,我们相信:过多“快餐”式的阅读只会令人“虚胖”,缺乏实质的内涵。伯乐在线内容团队正试图以我们微薄的力量,把优秀的原创文章和译文分享给读者,为“快餐”添加一些“营养”元素。
新浪微博:
推荐微信号
(加好友请注明来意)
– 好的话题、有启发的回复、值得信赖的圈子
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选文章
– UI,网页,交互和用户体验
– 专注iOS技术分享
– 专注Android技术分享
– JavaScript, HTML5, CSS
– 专注Java技术分享
– 专注Python技术分享
& 2016 伯乐在线谁能帮我分析一下C语言的这个程序_百度知道
谁能帮我分析一下C语言的这个程序
stdio,几天刚看到组数# include&lt我是一个初学者;for(i=0;,a[i])?还有.h&4;i&printf(&4;i++);i&i++),为什么前面学过的内容main前面没有int 这个int在这表示什么啊 我在计算机上执行的结果为 4 但是书上的结果是0 1 2 3 不过我的点那在执行的时候 出现了xxx内存不能为writen 可能计算机出问题了;int
main (){int a[4];}我不明白;%d &for(i=0;
返回值又是什么东西呢? 我刚学 什么都不懂 以前接触的 main前面既没有int有没有viod啊
提问者采纳
这类编译器还是会帮你写的;;4:由于“for(i=0:我刚学 什么都不懂 以前接触的 main前面既没有int有没有viod啊 答,这被所有的C编译器支持---------------------------------------------------------------------------------------- 补充;i++) a[i]=i,如果没这语句: 0 1 2 3 ----------------------------------------------------------------------------- 对你疑问的解答. 问,我写一个函数告诉你. 问;i<你要想了解返回值的作用的话;输出数组的值 for(i=0,我帮你改了 3;”去掉了 printf(&quot:在main()函数前没有int或void这个功能只被少数编译器支持; i++) &#47:a; } 如果没有“return c:第二个for语句有什么用吗.问;
/ int main () { int a[4]; /”;&#47? 答;i++) &#47,b /i++);给整型数组赋值 for(i=0;/还有就是;”这句话;i&lt,接着执行“a[i]=i;;你想下: 如果你还是不大明白,其作用是输出数组的值;输入;输出,a[i]); &#47. 问, int b) { for(i=0,通俗的说作用就是让使用这程序的人知道数组的值;功能? 答,虽然你没写出来;/4;4,让a[4]=4; ”后有& c=a+b; } --------------------------------------------------------------------------- 运行结果;&#47:c int add(我把这里的“:我在计算机上执行的结果为 4 但是书上的结果是0 1 2 3 不过我的点那在执行的时候 出现了xxx内存不能为writen 可能计算机出问题了;i&&quot:在main()中可以不写返回值;我把这里的“;///”去掉了 a[i]=i,你的这第二个for语句犯了和第一个for语句同样的错误;而不是像你想象的那样&quot,系统会帮你写;%d &i& &加了返回值 return 0:返回值又是什么东西呢? 答:进行加法运算 &#47:有用,这个程序运行起来就是个哑巴,于是系统认为你的循环体为空: &#47: 1。4;,请加我的百度为好友;/4;stdio,这条语句的作用就只是让i的值改为4,什么也不说了;我的建议就是在前面加上int------------------------------------------------------------------------------- 改后的代码;这个循环 2: #include&lt.h&gt,这个加法函数将不返回两个数相加的结果
提问者评价
很好,回答得很有条理,他们也回答得不错,但是只能选择一个,真有点对不起他们,呵呵
其他类似问题
为您推荐:
其他10条回答
%d &quot你前面学的mian没有int是缺省的 对于函数来说 前面如果没有类型的话 那么缺省就是int还有你2个for喜欢后面就加了,a[i]);号是错的;;i++){a[i]=i+1;4;;i&i++){printf(&quot,a[i])就是错的了改为for (i=0。你这样就只是给a[4]赋值但是 数组下标只是a[0]-a[3]所以你这个非法的但是标准C好像定义可以给数组后面的一个赋值 但是不能引用他就想你这样a[4]=4 是可以的 但是printf(&i&4;%d&}for(i=0。
main前面的int 表示返回值,在平常情况下没有作用,只有当该函数被调用时才起作用。如果没有int,那么就默认返回值为0。
你的代码有点错误,两个for(i=0;i&4;i++);后面不应该有分号,如果有分号,那么for循环就没有进去,也就是没有给数组赋值。当然会出现内存错误。
你把两个for语句后面的分号去点就行了
# include&stdio.h&
int main ()
for(i=0;i&4;i++)
for(i=0;i&4;i++)
printf(&%d &,a[i]);
返回值,举个例子:就是编的每一个程序都可以看成一个函数,就是有输入,有输出,这个输出就是返回值的一种。格式是return +结果
C语言中的函数有两种形式:1)有返回值,2)无返回值。有返回值的函数会把执行的结果(也就是你写这个函数的目的)返回到...
int main的int表示返回值:操作系统调用程序运行,在程序运行结束后会返回给操作系统一个结果,就是这个返回值。若没有返回值的话,根据编译器的不同可能会返回一个0值或随机数。与此同时,编译器往往会产生一个警告。第二个for循环的作用是循环输出数组中的数据。补充:返回值是调用一个函数后函数的执行结果,在C语言中一般将其存放在AX(或EAX)寄存器中返回。比如函数:double add(double a, double b){
return a+b;}会将a和b的值相加,然后返回给调用它的语句,如:double m=5;n=6;double x=add(m,n);则程序在运行时,会将函数add的返回值赋值给x。
首先帮你改成正确的,然后再解释:# include&stdio.h&int main (){
for (i=0;i&4;i++)
for(i=0;i&4;i++)
printf(&%d &,a[i]);
} }写c程序要注意养成良好的习惯,注意缩进和{ }的配合,第2个for 的作用是循环把数组的内容打印出来。main前面的int是应该有的,书上没有也对,缺省的时候是void即无返回型。现在的C标准变了,变成'显式'标明类型的了,就是说无论是什么都要写出来,无返回类型时要标为 void.不知道你是干什么的,如果不是做硬件的,建议你学习python 或 Ruby ,一个星期就可以学会,而且很实用。
前面的int是main函数的返回值,得返回个整型值。一般正确完成返回0,否则返回-1,所以printf语句后加个retun 0;你错误的原因是第二个for语句后面的;要去掉,就正确输出0123了,该for语句的作用是输出a【0】到a【3】的所有值,你看看是不是
main也是个函数 有int 代表有必须有返回值 就是末尾的包含return语句 这个返回值是返回个系统的 如果不想返回值就这样写 main() 末尾也不用加return 你运行后输出4 是因为你在 for 语句后面加上啦分号 for 后面是不能加分号的 否则将会当作一条独立的语句啦 应该去掉分号 想下面这样 for(i=0;i&4;i++) a[i]=i; for(i=0;i&4;i++) 就会输出 0 1 2 3 啦 第二条 for语句是 循环输出数组的每个元素 for(i=0;i&4;i++) printf(&%d &,a[i]);
int表示如果你的程序运行正常的话返还一个整数,而你在程序的最后应加一句return 0;如果你不喜欢的话就把
int main() 改成 void main()你改成这样试试:# include&stdio.h& int main () { int a[4]; int i,j; for(i=0;i&4;i++);{j=i; a[i]=j;} for(i=0;i&4;i++); printf(&%d &,a[i]); } 第二个for是为输出数组中元素用的,就是一个一个输出
分数很吸引人,刷一下
程序出错了两个for()后面的 &;& 都要去掉
不说了,他们说的都很好
c语言的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁谁能帮我写一下单片机检测程序啊_百度知道
谁能帮我写一下单片机检测程序啊
我外围用红外感应触发继电器来使工作电路工作 但是红外感应有时无法消抖 所以设计一个单片机程序来延时消抖
但是在延时过程中如果红外有触发 我的工作电路继续工作 延时时间内没有触发 就断电
我以前也学了单片机 不过忘了很多
希望哪位高手帮帮忙啦!
DJNZ R4.0ORG
DJNZ R2: JNB
提问者采纳
用C语言吧?就一个延时函数加一个初始值。。你这里有啥
其他类似问题
为您推荐:
其他4条回答
你应该将工作电路加一个电压保持的硬件,例如一个大电容等。如果是前者,到底你要问的是延时消抖需要提问还是延时时间工作电路断电导致单片机不能工作需要提问.0)进行判断。如果是后者你的问题没说清楚,延时程序中你应该在一定间隔内对你要判断的电平(例如P1
不明白你的意思。
有必要用单片机?
加个施密特触发器能解决你的问题吗
您可能关注的推广
单片机的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁君,已阅读到文档的结尾了呢~~
以硬件在线仿真的方式调试程序——所有资料文档均为本人悉心收集,全部是文档中的精品,绝对值得下载收藏!
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
以硬件在线仿真的方式调试程序
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口}

我要回帖

更多关于 怎么调试程序 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信