免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 4076 | 回复: 11
打印 上一主题 下一主题

一个全局指针很奇怪的问题,大家帮忙看看那 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-12-14 19:20 |只看该作者 |倒序浏览
在网上找了一段代码
写了一个测试程序,出现我百思不得其解的问题。
代码:
log.h

  1. /* -------------------------------------------------------------------------
  2. * log.h
  3.   * -------------------------------------------------------------------------
  4. */

  5. #ifndef __LOG_H
  6. #define __LOG_H

  7. #include <stdio.h>
  8. #include <semaphore.h>

  9. #define LOGLINE_MAX 1024

  10. typedef struct {
  11.     int fd;
  12.     sem_t sem;
  13.     int flags;
  14. } log_t;


  15. #define DEBUG 1
  16. #define INFO  2
  17. #define WARN  3
  18. #define ERROR 4
  19. #define FATAL 5

  20. /*
  21. * Logs to the logfile using printf()-like format strings.
  22. *
  23. * log_t - The value you got back from a log_open() call.
  24. * level - can be one of: DEBUG, INFO, WARN, ERROR, FATAL
  25. * fmt   - is a printf()-like format string, followed by the parameters.
  26. *
  27. * Returns 0 on success, or -1 on failure.
  28. */
  29. int lprintf( log_t *log, unsigned int level, char *fmt, ... );

  30. #define LOG_TRUNC   1<<0
  31. #define LOG_NODATE  1<<1
  32. #define LOG_NOLF    1<<2
  33. #define LOG_NOLVL   1<<3
  34. #define LOG_DEBUG   1<<4
  35. #define LOG_STDERR  1<<5
  36. #define LOG_NOTID   1<<6

  37. /*
  38. * Initializes the logfile to be written to with fprintf().
  39. *
  40. * fname - The name of the logfile to write to
  41. * flags - The bitwise 'or' of zero or more of the following flags:
  42. *          LOG_TRUNC   - Truncates the logfile on opening
  43. *          LOG_NODATE  - Omits the date from each line of the log
  44. *          LOG_NOLF    - Keeps from inserting a trailing '\n' when you don't.
  45. *          LOG_NOLVL   - Keeps from inserting a log level indicator.
  46. *          LOG_STDERR  - Sends log data to stderr as well as to the log.
  47. *                        (this not implemented yet)
  48. *
  49. * Returns NULL on failure, and a valid log_t (value > 0) on success.
  50. */
  51. log_t *log_open( char *fname, int flags );

  52. /*
  53. * Closes a logfile when it's no longer needed
  54. *
  55. * log  - The log_t corresponding to the log you want to close
  56. */
  57. void log_close( log_t *log );



  58. #endif

复制代码


log.c

  1. /* -------------------------------------------------------------------------
  2. * log.c - htun logging functions
  3.   * -------------------------------------------------------------------------
  4. */

  5. #include <stdio.h>
  6. #include <unistd.h>
  7. #include <semaphore.h>
  8. #include <stdarg.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <errno.h>
  12. #include <time.h>
  13. #include <pthread.h>
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <fcntl.h>

  17. #include "log.h"


  18. /* Allows printf()-like interface to file descriptors without the
  19. * complications that arise from mixing stdio and low level calls
  20. * FIXME: Needs date and time before logfile entries.
  21. */
  22. int lprintf( log_t *log, unsigned int level, char *fmt, ... ) {
  23.     int fd;
  24.     int rc;
  25.     va_list ap;
  26.     time_t now;
  27.     char date[50];
  28.     static char line[LOGLINE_MAX];
  29.     static char threadnum[10];
  30.     int cnt;
  31.     static char *levels[6] = { "[(bad)] ",
  32.                                "[debug] ",
  33.                                "[info ] ",
  34.                                "[warn ] ",
  35.                                "[error] ",
  36.                                "[fatal] " };

  37.     if(!log) return -1;

  38.     /* If this is debug info, and we're not logging it, return */
  39.     if( !(log->flags&LOG_DEBUG) && level == DEBUG ) return 0;
  40.     fd=log->fd;

  41.     /* Prepare the date string   日期*/
  42.     if( !(log->flags&LOG_NODATE) ) {
  43.         now=time(NULL);
  44.         strcpy(date,ctime(&now));
  45.         date[strlen(date)-6]=' ';
  46.         date[strlen(date)-5]='\0';
  47.     }

  48.     /*线程号*/
  49.     if( !(log->flags&LOG_NOTID) ) {
  50.         sprintf(threadnum, "(%lu) ", pthread_self());
  51.     }

  52.     cnt = snprintf(line, sizeof(line), "%s%s%s",
  53.                    log->flags&LOG_NODATE ? "" : date,
  54.                    log->flags&LOG_NOLVL  ? "" :
  55.                        (level > FATAL ? levels[0] : levels[level]),
  56.                    log->flags&LOG_NOTID  ? "" : threadnum);

  57.     va_start(ap, fmt);
  58.     vsnprintf(line+cnt, sizeof(line)-cnt, fmt, ap);    /*如果输入的日志过长会自动截取*/
  59.     va_end(ap);

  60.     line[sizeof(line)-1] = '\0';

  61.     if( !(log->flags&LOG_NOLF) ) {
  62.         /*chomp(line);*/
  63.         /*strcpy(line+strlen(line), "\n");*/
  64.     }

  65.     sem_wait(&log->sem);         /*用信号实现同步*/
  66.     rc = write(fd, line, strlen(line));
  67.     sem_post(&log->sem);

  68.     if( !rc ) errno = 0;
  69.     return rc;
  70. }

  71. log_t *log_open( char *fname, int flags ) {
  72.     log_t *log = malloc(sizeof(log_t));

  73.     if(!log) {
  74.         fprintf(stderr, "log_open: Unable to malloc()");
  75.         goto log_open_a;
  76.     }
  77.     log->flags=flags;
  78.     if( !strcmp(fname,"-") ) {
  79.         log->fd = 2;
  80.     } else {
  81.         log->fd = open(fname, O_WRONLY|O_CREAT|O_NOCTTY |
  82.                 (flags&LOG_TRUNC ? O_TRUNC : O_APPEND) , 0666);

  83.     }
  84.     if( log->fd == -1 ) {
  85.         fprintf(stderr, "log_open: Opening logfile %s: %s",
  86.                 fname, strerror(errno));
  87.         goto log_open_b;
  88.     }
  89.     if( sem_init(&log->sem, 0, 1) == -1 ) {
  90.         fprintf(stderr, "log_open: Could not initialize log semaphore.");
  91.         goto log_open_c;
  92.     }
  93.     return log;

  94. log_open_c:
  95.     close(log->fd);
  96. log_open_b:
  97.     free(log);
  98. log_open_a:
  99.     return NULL;
  100. }

  101. void log_close( log_t *log ) {
  102.     sem_wait(&log->sem);
  103.     sem_destroy(&log->sem);
  104.     close(log->fd);
  105.     free(log);
  106.     return;
  107. }

复制代码


测试程序:
log_t.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include "log.h"

  4. log_t *log;
  5. int
  6. main(int argc, char **argv)
  7. {
  8.     log = log_open("zzz.log", 0);
  9.     lprintf(log, INFO, "test %d\n", 1000);
  10.     lprintf(log, INFO, "test111111111111111111\n");
  11.     log_close(log);

  12.     return 0;
  13. }
复制代码


程序运行总是抱错:
Segmentation fault

gdb调试:

  1. (gdb) b main
  2. Breakpoint 1 at 0x8048bdc: file log_t.c, line 9.
  3. (gdb) r
  4. Starting program: /home/zang/186/thread_pool/zpksrc/log_t
  5. [Thread debugging using libthread_db enabled]
  6. [New Thread -1208314176 (LWP 7078)]
  7. [Switching to Thread -1208314176 (LWP 7078)]

  8. Breakpoint 1, main (argc=1, argv=0xbffdcbb4) at log_t.c:9
  9. 9               log = log_open("zpk.log", 0);
  10. (gdb) p &log
  11. $1 = (log_t **) 0x80495ac  //log_open 之前全局指针的地址
  12. (gdb) p log
  13. $2 = (log_t *) 0x0               //log_open 之前全局指针的值
  14. (gdb) n
  15. 10              lprintf(log, INFO, "test %d\n", 1000);
  16. (gdb) p &log
  17. $3 = (log_t **) 0x80495ac   //log_open 之后全局指针的地址
  18. (gdb) p log
  19. $4 = (log_t *) 0x828c008     //log_open 之后全局指针的值
  20. (gdb) n
  21. 11              lprintf(log, INFO, "test111111111111111111\n");
  22. (gdb) p &log
  23. $5 = (log_t **) 0x80495ac    //lprintf 之后的全局指针的地址
  24. (gdb) p log
  25. $6 = (log_t *) 0x8280020     //lprintf 之后的全局指针的值,就是在这里指针的值竟然发生了改变.这里指针的值应该是不发生改变
  26.                               //的,大家看看为什么?就是因为指针值的改变,所以下面那个lprintf产生了段错误
  27. (gdb)

复制代码


大家看看究竟是怎么回事?

呵呵。。。
thanks

论坛徽章:
0
2 [报告]
发表于 2006-12-14 19:21 |只看该作者
up..............

论坛徽章:
0
3 [报告]
发表于 2006-12-14 19:23 |只看该作者
如果测试的程序修改为:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include "log.h"

  4. int
  5. main(int argc, char **argv)
  6. {
  7.     log_t *log;
  8.     log = log_open("zzz.log", 0);
  9.     lprintf(log, INFO, "test %d\n", 1000);
  10.     lprintf(log, INFO, "test111111111111111111\n");
  11.     log_close(log);

  12.     return 0;
  13. }

复制代码


就是正确的

论坛徽章:
0
4 [报告]
发表于 2006-12-15 09:10 |只看该作者
wa..........没有人知道么?

论坛徽章:
0
5 [报告]
发表于 2006-12-15 12:59 |只看该作者
up........

论坛徽章:
0
6 [报告]
发表于 2006-12-15 13:02 |只看该作者

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include "log.h"
  4. log_t *log = NULL;
  5.    
  6. int
  7. main(int argc, char **argv)
  8. {
  9.     log = log_open("zzz.log", 0);
  10.     lprintf(log, INFO, "test %d\n", 1000);
  11.     lprintf(log, INFO, "test111111111111111111\n");
  12.     log_close(log);

  13.     return 0;
  14. }

复制代码


也是正确的。

论坛徽章:
0
7 [报告]
发表于 2006-12-15 14:24 |只看该作者
不知道:
初始化的全局变量:      分配在.data段中
未初始化的全局变量:    分配在.bss段中
竟然有这么大的差别么?
有没有知道的高手啊?

论坛徽章:
0
8 [报告]
发表于 2006-12-15 14:27 |只看该作者
头都大大了,看不懂啊,
什么是.data段啊!什么是bss段啊?

论坛徽章:
0
9 [报告]
发表于 2006-12-15 14:29 |只看该作者
初始化的全局变量:
代码的汇编代码:

  1.     .file   "log_t.c"
  2. .globl log
  3.     .bss
  4.     .align 4
  5.     .type   log, @object
  6.     .size   log, 4
  7. log:
  8.     .zero   4
  9.     .section    .rodata
  10. .LC0:
  11.     .string "zpk.log"
  12. .LC1:
  13.     .string "test %d\n"
  14. .LC2:
  15.     .string "test111111111111111111\n"
  16.     .text
  17. .globl main
  18.     .type   main, @function
  19. main:
  20.     pushl   %ebp
  21.     movl    %esp, %ebp
  22.     subl    $8, %esp
  23.     andl    $-16, %esp
  24.     movl    $0, %eax
  25.     addl    $15, %eax
  26.     addl    $15, %eax
  27.     shrl    $4, %eax
  28.     sall    $4, %eax
  29.     subl    %eax, %esp
  30.     subl    $8, %esp
  31.     pushl   $0
  32.     pushl   $.LC0
  33.     call    log_open
  34.     addl    $16, %esp
  35.     movl    %eax, log
  36.     pushl   $1000
  37.     pushl   $.LC1
  38.     pushl   $2
  39.     pushl   log
  40.     call    lprintf
  41.     addl    $16, %esp
  42.     subl    $4, %esp
  43.     pushl   $.LC2
  44.     pushl   $2
  45.     pushl   log
  46.     call    lprintf
  47.     addl    $16, %esp
  48.     subl    $12, %esp
  49.     pushl   log
  50.     call    log_close
  51.     addl    $16, %esp
  52.     movl    $0, %eax
  53.     leave
  54.     ret
  55.     .size   main, .-main
  56.     .section    .note.GNU-stack,"",@progbits
  57.     .ident  "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-3)"
复制代码



未初始化的全局变量:
代码的汇编代码:

  1.    .file   "log_t.c"
  2.     .section    .rodata
  3. .LC0:
  4.     .string "zpk.log"
  5. .LC1:
  6.     .string "test %d\n"
  7. .LC2:
  8.     .string "test111111111111111111\n"
  9.     .text
  10. .globl main
  11.     .type   main, @function
  12. main:
  13.     pushl   %ebp
  14.     movl    %esp, %ebp
  15.     subl    $8, %esp
  16.     andl    $-16, %esp
  17.     movl    $0, %eax
  18.     addl    $15, %eax
  19.     addl    $15, %eax
  20.     shrl    $4, %eax
  21.     sall    $4, %eax
  22.     subl    %eax, %esp
  23.     subl    $8, %esp
  24.     pushl   $0
  25.     pushl   $.LC0
  26.     call    log_open
  27.     addl    $16, %esp
  28.     movl    %eax, log
  29.     pushl   $1000
  30.     pushl   $.LC1
  31.     pushl   $2
  32.     pushl   log
  33.     call    lprintf
  34.     addl    $16, %esp
  35.     subl    $4, %esp
  36.     pushl   $.LC2
  37.     pushl   $2
  38.     pushl   log
  39.     call    lprintf
  40.     addl    $16, %esp
  41.     subl    $12, %esp
  42.     pushl   log
  43.     call    log_close
  44.     addl    $16, %esp
  45.     movl    $0, %eax
  46.     leave
  47.     ret
  48.     .size   main, .-main
  49.     .comm   log,4,4
  50.     .section    .note.GNU-stack,"",@progbits
  51.     .ident  "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-3)"
复制代码

论坛徽章:
0
10 [报告]
发表于 2006-12-15 14:35 |只看该作者
原帖由 绿茶主演 于 2006-12-15 14:27 发表
头都大大了,看不懂啊,
什么是.data段啊!什么是bss段啊?


  每个程序都有一个运行时存储器映像,如图3所示:

[ 本帖最后由 MackedNice 于 2006-12-15 14:39 编辑 ]

o_ctest2.jpg (22.38 KB, 下载次数: 39)

tu1

tu1
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP