代码之家  ›  专栏  ›  技术社区  ›  asio_guy

史崔托克的错误我这里漏了点东西

c
  •  1
  • asio_guy  · 技术社区  · 6 年前

    这是我的程序的一个片段

    #include <stdio.h>
    #include <string.h>
    void  something_wrong_really(char *str)
    {
            char *savedptr = NULL;
            char *delim    = " ";
    
            for ( char *p = str ; ; p = NULL) {
                    char *token = strtok_r(p, delim, &savedptr);
                    if (token == NULL)
                            break;
                    printf(" %s\n", token);
            }
    }
    
    int main(void) {
        char str[] = "Okay so lets split this and see how it works";
        something_wrong_really(str);
        return 0;
    }
    

    strtok_r manual

    strtok_r():_POSIX_C_源 /|BSD|u源| | SVID|u源

    如果我把程序编译成

    cc t.c -std=c99
    

    t.c: In function 'something_wrong_really':
    t.c:10:3: warning: implicit declaration of function 'strtok_r' [-Wimplicit-function-declaration]
       char *token = strtok_r(p, delim, &savedptr);
       ^
    t.c:10:17: warning: initialization makes pointer from integer without a cast [enabled by default]
       char *token = strtok_r(p, delim, &savedptr);
                     ^
    

    有什么比这更糟的吗 segfaults

    ./a.out
    Segmentation fault
    

    Program received signal SIGSEGV, Segmentation fault.
    0x00007ffff7a5af19 in vfprintf () from /lib64/libc.so.6
    Missing separate debuginfos, use: debuginfo-install glibc-2.17-222.el7.x86_64
    (gdb) bt
    #0  0x00007ffff7a5af19 in vfprintf () from /lib64/libc.so.6
    #1  0x00007ffff7a61339 in printf () from /lib64/libc.so.6
    #2  0x00000000004005e2 in something_wrong_really (str=0x7fffffffe0a0 "Okay") at t.c:13
    #3  0x0000000000400653 in main () at t.c:19
    (gdb)
    

     _SVID_SOURCE || _BSD_SOURCE || _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE
    

    相应的输出

    # cc t.c -std=c99 -D_BSD_SOURCE
    #
    #
    # ./a.out
     Okay
     so
     lets
     split
     this
     and
     see
     how
     it
     works
    #
    

    关于为什么会有这种行为有什么线索吗?


    所以这似乎是 strtok_r

    glibc的特性测试宏要求(参见 功能测试宏(7):

       strtok_r(): _POSIX_C_SOURCE
           || /* Glibc versions <= 2.19: */ _BSD_SOURCE || _SVID_SOURCE
    

    feature_test_macros

    ,必须进行以下宏定义之一 在包含任何头文件之前:

           #define _BSD_SOURCE
           #define _XOPEN_SOURCE        /* or any value < 500 */
    
       Alternatively, equivalent definitions can be included in the compila‐
       tion command:
    
           cc -D_BSD_SOURCE
           cc -D_XOPEN_SOURCE           # Or any value < 500
    

    因此,正如@someprogrammer dude指出的,包含这些宏定义是必须的,否则它将导致UB,这最终就是这里发生的事情。

    1 回复  |  直到 6 年前
        1
  •  3
  •   Some programmer dude    6 年前

    如果未使用正确的启用宏( _POSIX_C_SOURCE the manual page )那么函数将不会自动声明。这意味着编译器必须推导参数类型,更重要的是返回类型将自动 int

    undefined behavior ,很可能会撞车。

    通过添加正确的宏,函数将在头文件中正确声明,并且将使用参数和返回值的正确类型。


    char * 内景