Chinaunix

标题: printf为什么会这样? [打印本页]

作者: yuxh    时间: 2004-12-27 12:28
标题: printf为什么会这样?
看看这个程序的执行结果:
  1. char *Func(int n)
  2. {
  3.     static char s[20];

  4.     sprintf(s, "number %d", n);

  5.     return s;
  6. }

  7. main()
  8. {
  9.     printf("%s, %s\n", Func(1), Func(2));
  10. }
复制代码

为什么是number 1, number 1?
作者: aero    时间: 2004-12-27 12:40
标题: printf为什么会这样?
因为两个func的执行顺序不一定,取决于编译器。
你的程序,在你的编译器上,相当于:
func(2);
func(1);
printf……

你说是不是两个1呢?

尽量不要在printf参数中调用函数或进行任何运算。
作者: playmud    时间: 2004-12-27 12:56
标题: printf为什么会这样?
问题在于: static char s[20];
作者: playmud    时间: 2004-12-27 12:58
标题: printf为什么会这样?
应该是: static char s[20];
和printf的原因,真正的输出是在见到;的时候
作者: 思一克    时间: 2004-12-27 13:08
标题: printf为什么会这样?
c程序的参数都是从最右面一个开始入站的。和编译无关。可以改变次序,比如加PASCAL等函数说明--这和编译有关。
是static char S[]的问题。如果用MALLOC就可以了
作者: playmud    时间: 2004-12-27 13:17
标题: printf为什么会这样?
malloc也不可以,传递一个局部变量的指针是很危险的.
作者: yuxh    时间: 2004-12-27 13:23
标题: printf为什么会这样?
定义成全局char s[20]也是一样的
一个static的局部变量return出去没什么问题吧?
  1. int Func(int n)
  2. {
  3.     return n+1;
  4. }

  5. main()
  6. {
  7.     printf("%d, %d\n", Func(1), Func(2));
  8. }

复制代码
这个为什么就是 2, 3?
和地址有关。
作者: 思一克    时间: 2004-12-27 13:27
标题: printf为什么会这样?


  1. #include <stdio.h>;

  2. char *ma[4];
  3. int  mn = 0;

  4. char *Func(int n)
  5. {
  6. char *s = malloc(32);
  7.     ma[mn++] = s;
  8.     sprintf(s, "number %d", n);

  9.     return s;
  10. }

  11. main()
  12. {
  13. int i;

  14.     printf("%s, %s\n", Func(1), Func(2));

  15.     for(i = 0; i < mn; i++)
  16.       if(ma[i]) free(ma[i]);
  17.   
  18. }
复制代码

就可以了。
最后的free其实是多此一举的。
作者: aero    时间: 2004-12-27 13:30
标题: printf为什么会这样?
大家都木有认真看偶的解释啊。

1、参数中的函数的计算顺序,标准没有规定,由编译器来决定。所以建议不要使用这种方式。
2、yuxh的第二个例子和第一个例子一点都不冲突。你的编译器是从左到右计算参数的。
作者: converse    时间: 2004-12-27 13:30
标题: printf为什么会这样?

  1. char *Func(int n)
  2. {
  3.     static char s[20];

  4.     sprintf(s, "number %d", n);

  5.     return s;
  6. }

  7. main()
  8. {
  9.     printf("%s, %s\n", Func(1), Func(2));
  10. }

复制代码

应该是和压参数的顺序有关的,先压的是2的,然后压的是1的,而在调用printf的时候用了最后的那个1的所以。。。
作者: 思一克    时间: 2004-12-27 13:31
标题: printf为什么会这样?
还有,malloc返回的不是局部变量的指针!
作者: playmud    时间: 2004-12-27 13:38
标题: printf为什么会这样?
原帖由 "yuxh" 发表:
个为什么就是 2, 3?
和地址有关。

相当于:
int temp2=Func(2);
int temp1=Func(1);
    printf("%d, %d\n", temp1, temp2);

开始那个相当于:
static char * temp1=Func(1)=Func(2);

    printf("%s, %s\n", temp1, temp1);
作者: 思一克    时间: 2004-12-27 13:42
标题: printf为什么会这样?
to aero,
C都是从右向左压站的。和COMPILER无关
yuxh的例子也同样如此。
作者: playmud    时间: 2004-12-27 13:42
标题: printf为什么会这样?
[quote]原帖由 "思一克"]还有,malloc返回的不是局部变量的指针![/quote 发表:

哦?那返回的是什么?
作者: 思一克    时间: 2004-12-27 13:44
标题: printf为什么会这样?
malloc()返回的是在堆中的全局变量的指针。
作者: aero    时间: 2004-12-27 13:47
标题: printf为什么会这样?
我是说的参数计算顺序,又没说入栈顺序。yuxh的例子,明显是从左到右计算的参数。

话又说回来,的确一般的compiler都是从右至左入栈,但这个是标准规定的吗?我不清楚。
作者: 思一克    时间: 2004-12-27 13:53
标题: printf为什么会这样?
to aero,
计算次序==入站次序。
yuxh的例子也不例外。
关键是用不用公用的存储区域。
作者: playmud    时间: 2004-12-27 13:54
标题: printf为什么会这样?
啥时候成了全局变量了?
作者: converse    时间: 2004-12-27 13:55
标题: printf为什么会这样?
无可置疑,先调用的func(2),然后调用的func(1),见汇编代码,一切都清楚了:

  1. Disassembly of section .text:

  2. 00000000 <.text>;:
  3.    0:        6e                           outsb  %ds:(%esi),(%dx)
  4.    1:        75 6d                        jne    70 <_main+0x36>;
  5.    3:        62 65 72                     bound  %esp,0x72(%ebp)
  6.    6:        20 25 64 00 55 89            and    %ah,0x89550064

  7. 0000000a <_Func>;:
  8.    a:        55                           push   %ebp
  9.    b:        89 e5                        mov    %esp,%ebp
  10.    d:        83 ec 18                     sub    $0x18,%esp
  11.   10:        8b 45 08                     mov    0x8(%ebp),%eax
  12.   13:        89 44 24 08                  mov    %eax,0x8(%esp)
  13.   17:        c7 44 24 04 00 00 00         movl   $0x0,0x4(%esp)
  14.   1e:        00
  15.   1f:        c7 04 24 00 00 00 00         movl   $0x0,(%esp)
  16.   26:        e8 00 00 00 00               call   2b <_Func+0x21>;
  17.   2b:        b8 00 00 00 00               mov    $0x0,%eax
  18.   30:        c9                           leave  
  19.   31:        c3                           ret   
  20.   32:        25 73 2c 20 25               and    $0x25202c73,%eax
  21.   37:        73 0a                        jae    43 <_main+0x9>;
  22.         ...

  23. 0000003a <_main>;:
  24.   3a:        55                           push   %ebp
  25.   3b:        89 e5                        mov    %esp,%ebp
  26.   3d:        53                           push   %ebx
  27.   3e:        83 ec 14                     sub    $0x14,%esp
  28.   41:        83 e4 f0                     and    $0xfffffff0,%esp
  29.   44:        b8 00 00 00 00               mov    $0x0,%eax
  30.   49:        89 45 f8                     mov    %eax,0xfffffff8(%ebp)
  31.   4c:        8b 45 f8                     mov    0xfffffff8(%ebp),%eax
  32.   4f:        e8 00 00 00 00               call   54 <_main+0x1a>;
  33.   54:        e8 00 00 00 00               call   59 <_main+0x1f>;
  34.   59:        c7 04 24 02 00 00 00         movl   $0x2,(%esp);2入栈
  35.   60:        e8 a5 ff ff ff               call   a <_Func>;
  36.   65:        89 c3                        mov    %eax,%ebx
  37.   67:        c7 04 24 01 00 00 00         movl   $0x1,(%esp);1入栈
  38.   6e:        e8 97 ff ff ff               call   a <_Func>;
  39.   73:        89 5c 24 08                  mov    %ebx,0x8(%esp)
  40.   77:        89 44 24 04                  mov    %eax,0x4(%esp)
  41.   7b:        c7 04 24 32 00 00 00         movl   $0x32,(%esp)
  42.   82:        e8 00 00 00 00               call   87 <_main+0x4d>;
  43.   87:        8b 5d fc                     mov    0xfffffffc(%ebp),%ebx
  44.   8a:        c9                           leave  
  45.   8b:        c3                           ret   
  46.   8c:        90                           nop   
  47.   8d:        90                           nop   
  48.   8e:        90                           nop   
  49.   8f:        90                           nop   
复制代码

作者: aero    时间: 2004-12-27 13:56
标题: printf为什么会这样?
^_^,是了。看走眼了。是从右向左计算的。呵呵。
作者: playmud    时间: 2004-12-27 14:00
标题: printf为什么会这样?
[quote]原帖由 "converse"][/quote 发表:


那只是你的编译器是从右到左.
作者: 思一克    时间: 2004-12-27 14:01
标题: printf为什么会这样?
to: playmud
你觉得这样的程序有问题?

char *func()
{
char *s;

   ........ some code;

   return s;
}
有问题吗
作者: playmud    时间: 2004-12-27 14:02
标题: printf为什么会这样?

  1. 0x4012a8 <main>;:        push   %ebp
  2. 0x4012a9 <main+1>;:      mov    %esp,%ebp
  3. 0x4012ab <main+3>;:      push   %ebx
  4. 0x4012ac <main+4>;:      sub    $0x14,%esp
  5. 0x4012af <main+7>;:      and    $0xfffffff0,%esp
  6. 0x4012b2 <main+10>;:     mov    $0x0,%eax
  7. 0x4012b7 <main+15>;:     mov    %eax,0xfffffff8(%ebp)
  8. 0x4012ba <main+18>;:     mov    0xfffffff8(%ebp),%eax
  9. 0x4012bd <main+21>;:     call   0x401770 <_alloca>;
  10. 0x4012c2 <main+26>;:     call   0x4013e0 <__main>;
  11. 0x4012c7 <main+31>;:     movl   $0x2,(%esp,1)

  12. 0x4012ce <main+38>;:     call   0x401290 <_Z4Funci>;
  13. 0x4012d3 <main+43>;:     mov    %eax,%ebx
  14. 0x4012d5 <main+45>;:     movl   $0x1,(%esp,1)

  15. 0x4012dc <main+52>;:     call   0x401290 <_Z4Funci>;
  16. 0x4012e1 <main+57>;:     mov    %ebx,0x8(%esp,1)
  17. 0x4012e5 <main+61>;:     mov    %eax,0x4(%esp,1)

  18. 0x4012e9 <main+65>;:     movl   $0x401299,(%esp,1)
  19. 0x4012f0 <main+72>;:     call   0x401820 <printf>;
  20. 0x4012f5 <main+77>;:     movl   $0x4012a1,(%esp,1)
  21. 0x4012fc <main+84>;:     call   0x401810 <system>;
  22. 0x401301 <main+89>;:     mov    $0x0,%eax
  23. 0x401306 <main+94>;:     mov    0xfffffffc(%ebp),%ebx
  24. 0x401309 <main+97>;:     leave
  25. 0x40130a <main+98>;:     ret
  26. 0x40130b <main+99>;:     nop
  27. 0x40130c <main+100>;:    nop
  28. 0x40130d <main+101>;:    nop
  29. 0x40130e <main+102>;:    nop
  30. 0x40130f <main+103>;:    nop
  31. End of assembler dump.
复制代码

道的汇编代码怎么弄出来的?
作者: converse    时间: 2004-12-27 14:09
标题: printf为什么会这样?
我觉得还是有一点问题,在func中的汇编代码,leave之前的那一个:
2b:   b8 00 00 00 00          mov    $0x0,%eax
这个怎么解释?看不懂,这样的话每次返回回来的都是0x0呀??
作者: converse    时间: 2004-12-27 14:11
标题: printf为什么会这样?
>;>;道的汇编代码怎么弄出来的?
gcc -c 产生.o文件,然后objdump -d查看o文件就可以了
作者: playmud    时间: 2004-12-27 14:12
标题: printf为什么会这样?
原帖由 "思一克" 发表:
to: playmud
你觉得这样的程序有问题?

char *func()
{
char *s;

   ........ some code;

   return s;
}
有问题吗


是的,我觉得有问题.
char * s=(char *)malloc(40);
return s;
func()调用结束以后他的局部变量会被释放掉,尽管str是在堆上分配的空间,我认为这个空间会在
这个函数调用结束以后释放资源,而return的结果是指向这个空间的一个地址,所以不安全.
作者: playmud    时间: 2004-12-27 14:15
标题: printf为什么会这样?
c/c++确实压栈的顺序是函数参数相反的顺序.这个我上面错了!
作者: 思一克    时间: 2004-12-27 14:17
标题: printf为什么会这样?
to playmud,

你错了。malloc()的内存func()返回时不会释放掉。
至于变量s, 会释放掉,但释放并不影响返回。

就如同:

int func()
{
int i;
   i = 5;
   return i;
}
正确一样。(i 不也“释放”掉了吗)
作者: playmud    时间: 2004-12-27 14:21
标题: printf为什么会这样?
原帖由 "converse" 发表:
>;>;道的汇编代码怎么弄出来的?
gcc -c 产生.o文件,然后objdump -d查看o文件就可以了
z
学了一招!!我用gdb里面的disassemble 如何能到到上面的效果?
作者: aero    时间: 2004-12-27 14:22
标题: printf为什么会这样?
原帖由 "converse" 发表:
我觉得还是有一点问题,在func中的汇编代码,leave之前的那一个:
2b:   b8 00 00 00 00          mov    $0x0,%eax
这个怎么解释?看不懂,这样的话每次返回回来的都是0x0呀??


我的不是这样啊,你用的是那个源码啊?给我试试。
作者: playmud    时间: 2004-12-27 14:25
标题: printf为什么会这样?
原帖由 "思一克" 发表:
to playmud,

你错了。malloc()的内存func()返回时不会释放掉。
至于变量s, 会释放掉,但释放并不影响返回。

就如同:

int func()
{
int i;
   i = 5;
   return i;
}
正确一样。(i 不也“释放”掉?.........


上面的这个没有问题,因为他传递的是一个值,
int i=func();
这个没有问题的,但是如果是char *的话就有问题了,
char * str=(char *)malloc(100);
str=func();
这样str原来分配的空间就泄漏了.
作者: aero    时间: 2004-12-27 14:25
标题: printf为什么会这样?
原帖由 "playmud" 发表:

学了一招!!我用gdb里面的disassemble 如何能到到上面的效果?


?啥效果。gdb就是gdb的显示方法,^_^。

另外,你们为啥都不用gcc的-S参数啊?然后直接看.s文件,多方便啊?不像dump出来的,全是立即数。
作者: aero    时间: 2004-12-27 14:28
标题: printf为什么会这样?
原帖由 "playmud" 发表:


上面的这个没有问题,因为他传递的是一个值,
int i=func();
这个没有问题的,但是如果是char *的话就有问题了,
char * str=(char *)malloc(100);
str=func();
这样str原来分配的空间就泄漏了.


str这个变量的4个字节空间是释放了。可是它分配的空间没有释放,这个你也明白,你说它是泄漏了。其实如果函数返回的时候,将str的值传出来,调用函数再精确的进行控制和处理,这段空间还是可控的,不算是泄漏的。
作者: playmud    时间: 2004-12-27 14:28
标题: printf为什么会这样?
原帖由 "aero" 发表:


?啥效果。gdb就是gdb的显示方法,^_^。

另外,你们为啥都不用gcc的-S参数啊?然后直接看.s文件,多方便啊?不像dump出来的,全是立即数。

呵呵,初学者,又学一手!
作者: 思一克    时间: 2004-12-27 14:30
标题: printf为什么会这样?
to playmud,

我再重复:

char *func()
{
char *s;

    s = malloc(1234);
    return s;
}
是正确的。
我无法再详细说了,你可以问aero或斑竹win_hate, flw等。
作者: playmud    时间: 2004-12-27 14:41
标题: printf为什么会这样?
原帖由 "aero" 发表:


str这个变量的4个字节空间是释放了。可是它分配的空间没有释放,这个你也明白,你说它是泄漏了。其实如果函数返回的时候,将str的值传出来,调用函数再精确的进行控制和处理,这段空间还是可控的,不算是泄漏的。

这样说是没错,但是不能提倡这么做.
作者: unicorns    时间: 2004-12-27 14:44
标题: printf为什么会这样?
原帖由 "思一克" 发表:
to playmud,

我再重复:

char *func()
{
char *s;

    s = malloc(1234);
    return s;
}
是正确的。
我无法再详细说了,你可以问aero或斑竹win_hate, flw等。


正确是没的说的.

不过顺便说下
我始终觉得这样在函数内部分配空间的做法不大安全.呵呵
比如我就在程序里看到有人这么用function(var1, strdup(str1), strdup(str2));
显然strdup里分配的内存就再也找不回来了.function里可不知道这指针指向的内存是哪儿来的,他也管不着啊.

不是说冲击波老是要强制关机就是因为频繁使用strdup而没有释放内存造成的么.
作者: aero    时间: 2004-12-27 14:44
标题: printf为什么会这样?
原帖由 "playmud" 发表:

这样说是没错,但是不能提倡这么做.


   有原则是好事,但也有灵活对待。

dup类的系统函数不就是这样的利用方法吗?
作者: playmud    时间: 2004-12-27 14:54
标题: printf为什么会这样?
原帖由 "思一克" 发表:
to playmud,

我再重复:

char *func()
{
char *s;

    s = malloc(1234);
    return s;
}
是正确的。
我无法再详细说了,你可以问aero或斑竹win_hate, flw等。


不见得是正确的.程序员应该严谨.
而且这种做法是不提倡的,资源的申请和释放应该在同一个层次里面.
作者: yuxh    时间: 2004-12-27 16:58
标题: printf为什么会这样?
思一克正确,malloc不都是这样用的?
作者: assiss    时间: 2004-12-27 17:30
标题: printf为什么会这样?
又来晚了,大家都讨论完了.只好坐板凳.
作者: twen345    时间: 2004-12-27 18:38
标题: printf为什么会这样?
原帖由 "思一克" 发表:
to playmud,

我再重复:

char *func()
{
char *s;

    s = malloc(1234);
    return s;
}
是正确的。
我无法再详细说了,你可以问aero或斑竹win_hate, flw等。

正确的,也是一种习惯用法,比如库函数strdup:
  1. char *strdup(char *s)
  2.           {
  3.                char *p;

  4.                 p = (char *)malloc(strlen(s) + 1);
  5.                 if (p != NULL)
  6.                         strcpy(p, s);
  7.                 return p;
  8.            }  
复制代码

大概就是这样实现的
作者: playmud    时间: 2004-12-27 19:47
标题: printf为什么会这样?
s = malloc(1234);
这种把s声明为char *,非配空间的时候不加说明的,我这里编译不过去.
作者: aero    时间: 2004-12-27 19:51
标题: printf为什么会这样?
原帖由 "playmud" 发表:
s = malloc(1234);
这种把s声明为char *,非配空间的时候不加说明的,我这里编译不过去.


你用的是啥环境啊?啥编译器啊?
作者: playmud    时间: 2004-12-27 20:13
标题: printf为什么会这样?
g++
作者: aero    时间: 2004-12-27 20:18
标题: printf为什么会这样?
能过去啊,你的code贴上来吧。不可能出问题的。
作者: playmud    时间: 2004-12-27 20:30
标题: printf为什么会这样?


  1. #include <stdlib.h>;

  2. int main()
  3. {
  4. char *str;
  5. str=malloc(100);
  6. }
复制代码


你的可以通过?

6 test.cpp invalid conversion from `void*' to `char*'

你的编译器是不是检查不严格?
作者: twen345    时间: 2004-12-27 20:33
标题: printf为什么会这样?
原帖由 "playmud" 发表:

你的可以通过?

6 test.cpp invalid conversion from `void*' to `char*'

你的编译器是不是检查不严格?

C和C++的区别,用gcc可以通过
作者: aero    时间: 2004-12-27 20:33
标题: printf为什么会这样?
靠,晕死。这个提示,那就改一下呗。还以为是啥大问题呢。我也是改过的。
作者: playmud    时间: 2004-12-27 20:35
标题: printf为什么会这样?
就是gcc通过不了,我在上面说了,程序员需要严谨.
作者: ificanfly    时间: 2004-12-27 20:49
标题: printf为什么会这样?
[quote]原帖由 "playmud"]就是gcc通过不了,我在上面说了,程序员需要严谨.[/quote 发表:

晕死!!!
要搞清楚什么是警告什么是错误。
严谨是需要的,但是也要灵活,当然灵活不是瞎灵活,保证在正确的范畴内
作者: win_hate    时间: 2004-12-27 20:57
标题: printf为什么会这样?
原帖由 "playmud" 发表:


不见得是正确的.程序员应该严谨.
而且这种做法是不提倡的,资源的申请和释放应该在同一个层次里面.


思一克说得对。

很多程序都这么干,如 gtk. 更极端的例子,见yuxh 的回帖。
作者: playmud    时间: 2004-12-27 20:58
标题: printf为什么会这样?
上面是警告吗?
编译器: Default compiler
执行  g++.exe...
g++.exe "D:\temp\test.cpp" -o "D:\temp\test.exe"    -I"D:\Dev-Cpp\include\c++\3.3.1"  -I"D:\Dev-Cpp\include\c++\3.3.1\mingw32"  -I"D:\Dev-Cpp\include\c++\3.3.1\backward"  -I"D:\Dev-Cpp\lib\gcc-lib\mingw32\3.3.1\include"  -I"D:\Dev-Cpp\include"   -L"D:\Dev-Cpp\lib"
D:/temp/test.cpp: In function `int main()':
D:/temp/test.cpp:6: error: invalid conversion from `void*' to `char*'

执行结束
作者: twen345    时间: 2004-12-27 20:58
标题: printf为什么会这样?
[quote]原帖由 "playmud"]就是gcc通过不了,我在上面说了,程序员需要严谨.[/quote 发表:
  1. [twen@Danny test]$ gcc -Wall malloc.c
  2. [twen@Danny test]$ ./a.out
  3. success, no error!
  4. [twen@Danny test]$ cat malloc.c

  5. #include <stdlib.h>;
  6. #include <stdio.h>;

  7. int main()
  8. {
  9. char *str;
  10. str=malloc(100);
  11. printf(" success, no error!\n");
  12. return 0;
  13. }
  14. [twen@Danny test]$


复制代码

作者: playmud    时间: 2004-12-27 21:05
标题: printf为什么会这样?
你看看cpp
作者: win_hate    时间: 2004-12-27 21:09
标题: printf为什么会这样?

  1. char *Func(int n)
  2. {
  3.     static char s[20];

  4.     sprintf(s, "number %d", n);

  5.     return s;
  6. }

  7. main()
  8. {
  9.     printf("%s, %s\n", Func(1), Func(2));
  10. }
复制代码

[root@PPC ftp]# ./a.out
number 2, number 2
[root@PPC ftp]#


  1.         stwu 1,-32(1)
  2.         mflr 0
  3.         stw 29,20(1)
  4.         stw 31,28(1)
  5.         stw 0,36(1)
  6.         mr 31,1
  7.         li 3,1       <== 1
  8.         bl Func      <== Func(1)
  9.         mr 29,3
  10.         li 3,2       <=== 2
  11.         bl Func      <=== Func(2)
  12.         mr 0,3
  13.         lis 9,.LC1@ha
  14.         la 3,.LC1@l(9)
  15.         mr 4,29
  16.         mr 5,0
  17.         crxor 6,6,6
  18.         bl printf
  19.         mr 3,0
复制代码

作者: twen345    时间: 2004-12-27 21:10
标题: printf为什么会这样?
原帖由 "twen345" 发表:

C和C++的区别,用gcc可以通过

g++ != gcc
作者: yangtou    时间: 2004-12-27 21:11
标题: printf为什么会这样?
原帖由 "playmud" 发表:
上面是警告吗?
编译器: Default compiler
执行  g++.exe...
g++.exe "D:\temp\test.cpp" -o "D:\temp\test.exe"    -I"D:\Dev-Cpp\include\c++\3.3.1"  -I"D:\Dev-Cpp\include\c++\3.3.1\mingw32"  -I"D:\Dev-Cpp..........
类型检查错误,c++才会这样
作者: twen345    时间: 2004-12-27 21:15
标题: printf为什么会这样?
[quote]原帖由 "yangtou"]嘈图觳榇砦螅琧++才会这样[/quote 发表:

就是这个意思,c++要求void *赋值时必须显式转换
作者: playmud    时间: 2004-12-27 21:45
标题: printf为什么会这样?
gcc也一样,呵呵.
主要是cpp对类型检测比c严格.
作者: win_hate    时间: 2004-12-27 21:54
标题: printf为什么会这样?
原帖由 "playmud" 发表:
gcc也一样,呵呵.
主要是cpp对类型检测比c严格.



cpp 怎么会给出这个警告?

cpp 不懂 c 语法,预处理器不是 c 的组成部分。
作者: playmud    时间: 2004-12-27 22:03
标题: printf为什么会这样?
cpp对类型检测比较严格.
作者: gvim    时间: 2004-12-27 22:13
标题: printf为什么会这样?
cpp是C PreProcessor的缩写。
C++是C Plus Plus语言的缩写。
playmud不要搞混淆了,win_hate的cpp是指的前者。
作者: THEBEST    时间: 2004-12-27 22:17
标题: printf为什么会这样?
[quote]原帖由 "playmud"]cpp对类型检测比较严格.[/quote 发表:

CPP是指C鸡鸡吧?

比较严格是什么意思?把cout和printf比一下就这样?
作者: DonnyZXT    时间: 2004-12-27 22:43
标题: printf为什么会这样?
那是因为内在分配问题,虽然是两次调用函数,但其实是访问一个地址,也就是说s只有一个在Func(2)后是"number 2"但在Func(1)后就变成"number 1"了
作者: yuxh    时间: 2004-12-28 08:26
标题: printf为什么会这样?
原帖由 "win_hate"][root@PPC ftp 发表:
# ./a.out
number 2, number 2
[root@PPC ftp]#

也就是说参数入栈的次序是不确定的,随编译器而不同?
从左到右入栈,进入函数之后不是得首先把所有的参数全都弹出到形参?对于象printf这种参数个数不确定的函数,不知道怎么实现的?
总而言之,把函数作为参数是不安全的。
作者: FH    时间: 2004-12-28 09:52
标题: printf为什么会这样?
这么简单的问题还在没完的讨论么?
因为执行到printf函数的时候,Func(1)、Func(2)都已经执行完毕,printf只是打印堆栈里存的那个地址下的数据,因此两次的结果必然相同。
至于是打印1还是2则要看系统的压栈顺序,并非与编译器相关。
作者: asdmonster    时间: 2004-12-28 10:38
标题: printf为什么会这样?
原帖由 "FH" 发表:
这么简单的问题还在没完的讨论么?
因为执行到printf函数的时候,Func(1)、Func(2)都已经执行完毕,printf只是打印堆栈里存的那个地址下的数据,因此两次的结果必然相同。
至于是打印1还是2则要看系统的压栈顺序,..........

系统压栈顺序?这个顺序不是编译器给的吗?
作者: FH    时间: 2004-12-28 11:23
标题: printf为什么会这样?
呵呵,是俺糊涂了,谢谢指正。
不过,每个系统都有自己内定的参数顺序,编译器在该平台的实现也必须遵从这一顺序,因此从某种角度来看,也可以认为与编译器无关吧?
呵呵,以上属于“强词夺理”。
作者: win_hate    时间: 2004-12-28 11:57
标题: printf为什么会这样?
[quote]原帖由 "yuxh" 发表:

也就是说参数入栈的次序是不确定的,随编译器而不同?
从左到右入栈,进入函数之后不是得首先把所有的参数全都弹出到形参?对于象printf这种参数个数不确定的函数,不知道怎么实现的?
总而言之,把函数作为参数
作者: 思一克    时间: 2004-12-28 11:58
标题: printf为什么会这样?
标准C的压栈次序(也是计算参数的次序)是从右到左,和系统,编译都无关,是标准C必须遵循的。
要在C程序中改变这个次序,有些编译可以定义函数的修饰符,如PASCAL等。
标准PASCAL是从左到右。
作者: win_hate    时间: 2004-12-28 12:09
标题: printf为什么会这样?
我在 loveunix 上的一篇旧文,也许可以参考一下:

http://www.loveunix.net/bbs/index.php?showtopic=18640
作者: playmud    时间: 2004-12-28 12:31
标题: printf为什么会这样?
原帖由 "思一克" 发表:
标准C的压栈次序(也是计算参数的次序)是从右到左,和系统,编译都无关,是标准C必须遵循的。
要在C程序中改变这个次序,有些编译可以定义函数的修饰符,如PASCAL等。
标准PASCAL是从左到右。

我看的一些文章也是说压栈顺序是c决定的,和平台,编译器无关.
作者: unicorns    时间: 2004-12-28 12:57
标题: printf为什么会这样?
原帖由 "win_hate" 发表:


参数传递的方式取决于 ABI,编译器必须遵循系统所使用的 ABI,这样编译出来的程序或库才能与其他程序或库协同工作。

比如我给出的例子,那是 ppc32 的  SVR4 abi,其参数首先从寄存器传递,所以在参数个数不是..........


能不能稍微详细的讲解一下.
从教材上学到的都是说在调用函数的过程中
都是一个压栈保护现场,调用完毕后出栈恢复现场的过程.
我也一直没想去深究过.
不是很理解压栈与否取决与参数多寡.
作者: yangtou    时间: 2004-12-28 14:38
标题: printf为什么会这样?
有些体系约定有某几个通用寄存器来保存函数参数,只有这些寄存器用完了才压栈。
作者: aero    时间: 2004-12-28 15:31
标题: printf为什么会这样?
[quote]原帖由 "yangtou"]有些体系约定有某几个通用寄存器来保存函数参数,只有这些寄存器用完了才压栈。[/quote 发表:


^_^,比如sparc。
作者: flw    时间: 2004-12-28 16:22
标题: printf为什么会这样?
呵呵。
作者: FH    时间: 2004-12-28 16:59
标题: printf为什么会这样?
我觉得只要考虑逻辑上的压栈就行了。
把各硬件的实际策略也扯进来,初学者会更摸不着头脑。
作者: win_hate    时间: 2004-12-28 17:38
标题: printf为什么会这样?
原帖由 "playmud" 发表:

我看的一些文章也是说压栈顺序是c决定的,和平台,编译器无关.

原帖由 "ISO/IEC 9899:1999(E)" 发表:


3.4.4
1 unspecified behavior
behavior where this International Standard provides two or more possibilities
imposes no further requirements on which is chosen in any instance

2 EXAMPLE An example of unspecified behavior is the order in which the arguments
to a function evaluated.

作者: aero    时间: 2004-12-28 22:42
标题: printf为什么会这样?
win_hate,这个标准给偶一份好吗?
作者: assiss    时间: 2004-12-28 22:56
标题: printf为什么会这样?
[quote]原帖由 "aero"]win_hate,这个标准给偶一份好吗?[/quote 发表:
怎么aero一直没标准?这可不行啊,就快当版主的人了,呵呵,没个镇山之宝怎么行呢?
http://www.nirvani.net/docs/ansi_c.pdf
作者: aero    时间: 2004-12-28 23:14
标题: printf为什么会这样?
^_^,多谢。
作者: (︶ε︶)    时间: 2004-12-29 23:23
标题: printf为什么会这样?
程序1:
#include <stdio.h>;
char* magic(char *a)
{
    static char s[20];
    sprintf(s,"%s",a);
        return s;
}

void main()
{
    printf("%s %s\n",magic("1",magic("2");
}
这个明白。

程序2:
#include <stdio.h>;

int* magic(int n)
{
        static int a;
        a=n;
        return &amp;
}

void main()
{

    printf("%d %d\n",*(magic(1)),*(magic(2)));
}

程序3:
#include <stdio.h>;
char* magic(char a)
{
    static char s;
        s=a;
    return &amp;
}

void main()
{

    printf("%c %c\n",*(magic('1')),*(magic('2')));
}

VC6.0
程序1结果为:     1 1
为什么程序2与3结果为:      1 2
???
作者: christmaschd    时间: 2004-12-30 02:05
标题: printf为什么会这样?
#include<stdio.h>;
#include<string.h>;
#include<malloc.h>;
#include <stdlib.h>;

char *getFilePath()
        {        char *p = NULL;
                p = malloc(sizeof(char *));
                strcpy(p,"Fan a!";
                return p;
        }
int main(void){
        char *k=NULL;
        k = getFilePath();
        printf("FilePath is %s",k);
        free(k);
}
请教高手,这段代码在最后free(k);的时候为什么会出错??
有在线的朋友给个答案先,搞不明白晚上睡觉不安稳^_^
作者: yuxh    时间: 2004-12-30 08:50
标题: printf为什么会这样?
p = malloc(sizeof(char *));

sizeof(char *) = 一个字长,32位系统中是4
strcpy(p, "Fan a!";溢出了
作者: yuxh    时间: 2004-12-30 08:56
标题: printf为什么会这样?
[quote]原帖由 "(︶ε︶)"]printf("%s %s\n",magic("1",magic("2"); [/quote 发表:

这里按从右到左的顺序入栈的话,先调用magic("2",把return 的地址入栈
再调用magic("1"(这时s的内容发生变化了),再把return的地址入栈,printf打印这两个地址(相同)的字符串,结果是1 1

[quote]原帖由 "(︶ε︶)"]printf("%d %d\n",*(magic(1)),*(magic(2))); [/quote 发表:

*(magic(1))的值是1,入栈的是1而不是a的地址,因而入栈的是2,1,结果就是1 2

第三个一样
作者: assiss    时间: 2004-12-30 10:58
标题: printf为什么会这样?
原帖由 "yuxh" 发表:

*(magic(1))的值是1,入栈的是1而不是a的地址,因而入栈的是2,1,结果就是1 2

第三个一样
不一定的.看来跟编译器有关.我在VC6.0里结果跟他的一样,是1,2
但在gcc3.3.1+mingw里是1,1,第二题第三题都是这样.

修改:对不起,这里说错了,应该改为:
但在gcc3.3.1+mingw里第二题是1,1,第三题是1,2.
作者: aero    时间: 2004-12-30 11:04
标题: printf为什么会这样?
一句错话,^_^,编辑掉了。
作者: 思一克    时间: 2004-12-30 12:25
标题: printf为什么会这样?
下例子的程序(根据前面朋友改的)结果
在什么系统上都应该是
1   1
1   2
1   2
没有疑问。



  1. #include <stdio.h>;

  2. char* magic1(char *a)
  3. {
  4. static char s[20];
  5. sprintf(s,"%s",a);
  6. return s;
  7. }
  8. void main()
  9. {
  10. printf("example 1: %s %s\n",magic1("1"),magic1("2"));
  11. main2();
  12. main2();
  13. }
  14. int* magic2(int n)
  15. {
  16. static int a;
  17. a=n;
  18. return &
  19. }
  20. void main2() { printf("example 2:  %d %d\n",*(magic2(1)),*(magic2(2))); }

  21. char* magic3(char a)
  22. {
  23. static char s;
  24. s=a;
  25. return &
  26. }
  27. void main3() { printf("example 3:  %c %c\n",*(magic3('1')),*(magic3('2'))); }

复制代码

作者: assiss    时间: 2004-12-30 12:39
标题: printf为什么会这样?

  1. #include <stdio.h>;
  2. int* magic2(int n)
  3. {
  4.     static int a;
  5.     a=n;
  6.     return & a;
  7. }
  8. void main2()
  9. {
  10.     printf("example 2:  %d %d\n",*(magic2(1)),*(magic2(2)));
  11. }

  12. char* magic3(char a)
  13. {
  14.     static char s;
  15.     s=a;
  16.     return & s;
  17. }
  18. void main3()
  19. {
  20.     printf("example 3:  %c %c\n",*(magic3('1')),*(magic3('2')));
  21. }
  22. char* magic1(char *a)
  23. {
  24.     static char s[20];
  25.     sprintf(s,"%s",a);
  26.     return s;
  27. }
  28. int main()
  29. {
  30.     printf("example 1: %s %s\n",magic1("1"),magic1("2"));
  31.     main2();
  32.     main3();
  33.     return 0;
  34. }
复制代码

gcc3.3.1+mingw
结果:
----------运行 ----------
example 1: 1 1
example 2:  1 1
example 3:  1 2

输出完成 (耗时 0 秒) - 正常终止

VC6.0
结果:
example 1: 1 1
example 2:  1 2
example 3:  1 2
Press any key to continue

作者: hahubitbear    时间: 2004-12-30 12:50
标题: printf为什么会这样?
原帖由 "aero" 发表:
我是说的参数计算顺序,又没说入栈顺序。yuxh的例子,明显是从左到右计算的参数。

话又说回来,的确一般的compiler都是从右至左入栈,但这个是标准规定的吗?我不清楚。

参数计算应该和入栈顺序一致。
这里入栈的两个指针是相同的,所以内容也是相同的,
从右到左顺序,先print2再print1,所以2被1覆盖了。
作者: win_hate    时间: 2004-12-30 12:52
标题: printf为什么会这样?
用的是 assiss  的代码:

win/lcc4
example 1: 2 2
example 2: 2 2
example 3: 2 2

"d:\opt\lcc\lcc\test.exe"
Return code 0
Execution time 0.016 seconds
Press any key to continue...

作者: (︶ε︶)    时间: 2004-12-30 13:05
标题: printf为什么会这样?
原帖由 "yuxh" 发表:

*(magic(1))的值是1,入栈的是1而不是a的地址,因而入栈的是2,1,结果就是1 2

第三个一样

为什么入栈的是值而不是地址呢???
作者: (︶ε︶)    时间: 2004-12-30 13:06
标题: printf为什么会这样?
越发的糊涂了,郁闷啊
作者: 思一克    时间: 2004-12-30 13:09
标题: printf为什么会这样?
to assiss,

mingw是什么? 编译器是不是有问题?
你那个程序改的更好了,就拿它做例子。
作者: (︶ε︶)    时间: 2004-12-30 13:22
标题: printf为什么会这样?
我明白了,谢谢解答
作者: 思一克    时间: 2004-12-30 13:32
标题: printf为什么会这样?
To AERO,

你怎么还认为计算从左到右,是说yuxh的这个程序例子吗?

char *Func(int n)
{
    static char s[20];

    sprintf(s, "number %d", n);

    return s;
}

main()
{
    printf("%s, %s\n", Func(1), Func(2));
}

结果是number 1, number 1?
作者: aero    时间: 2004-12-30 13:36
标题: printf为什么会这样?
原帖由 "思一克" 发表:

    sprintf(s, "number %d", n);

    return s;
}

main()
{
    printf("%s, %s\n", Func(1), Func(2));
}

结果是number 1, number 1?


呵呵,不好意思,一直在忙别的。上来看一眼就冒胡话了。还没来得及编辑,终于被逮到了。^_^。
作者: 思一克    时间: 2004-12-30 13:46
标题: printf为什么会这样?
To aero,

你真逗。我逮到你了?
都到岁末了还这么忙?
预祝新年好
作者: aero    时间: 2004-12-30 13:48
标题: printf为什么会这样?
呵呵,是啊,是啊。
其实,还是这个问题的理解不好。有点顽固。
刚才仔细看了一下汇编码,这回印象深刻了。
^_^,真的要多谢你呢。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2