在Windows下用cygwin编译的C程序可以运行,在Linux下会出现分段错误。 cygwin GCC“不好”吗?

发布于 2024-07-13 13:53:17 字数 4379 浏览 6 评论 0原文

在我的编程 102 课程中,我们被要求提供在 Linux 下编译和运行的 C 代码。 我的硬盘上没有足够的空闲空间来安装 Linux 和 Windows,因此我使用 cygwin 来编译我的程序。

我必须提供的最新程序在 cygwin 下编译并运行良好。 它在 Linux 下编译得很好,但执行到一半时会产生分段错误。 我向给我们上课的研究生解释了这一点,他说 cygwin 版本的 GCC 允许编译和执行更草率的代码。

我通过谷歌找到的一些参考文献还不是结论性的。 我发现一个线程说Linux下seg错误的原因是内存泄漏。 为什么这不会影响 cygwin 版本?

我会使用大学的计算机,但我不能在它们上使用 Subversion,这会严重阻碍我的工作。 (我是编码新手,经常需要能够恢复到 X 版本之前的版本)。

cygwin 版本的 GCC 编译的代码真的更“宽松”吗? 如果是这样,编码时是否有任何明显的问题需要注意? 是否有其他方法可以编写在 Linux 下运行的代码?

编辑

感谢您的回复。 我在原来的帖子中不够明确:我的代码中存在一个错误对我来说几乎是理所当然的(我对编程很陌生,毕竟,当涉及到 C 时,我真的很绿)。 我的助教暗示 cygwin 的 GCC 是一种比 GNU/Linux 下的编译器更不可靠的编译器 - 允许运行更草率的代码。 我发现这很奇怪,因此在互联网上进行了搜索,但找不到任何与该事实相关的参考资料。

我不只是把责任归咎于编译器和我的代码,我还想知道程序在 Windows 下运行而在 Linux 下崩溃的原因是什么。 关于 Windows/Linux 下不同的内存管理器和堆/堆栈布局的答复在这方面进行了说明。

cygwin 的 GCC 与 GNU/Linux 一样“好”,并且我的有缺陷的程序在其中一个操作系统下运行而不是在另一个操作系统下运行是底层操作系统/纯粹是运气,这样的结论是否非常正确?

关于发布源代码,这是一项家庭作业,所以如果可能的话,我更愿意自己找到问题:)

编辑2

我已经接受了 jalf 的回答,因为它讨论了程序运行的原因在 Windows 下而不是在 Linux 下,这是我真正想知道的。 感谢所有其他贡献者,他们的回复都非常有趣且内容丰富。

当我发现问题并修复它时,我将上传一个包含此非工作版本的所有源代码的 zip 文件,以防有人好奇我到底做了什么:)

编辑 3

,我发现了问题,而且确实是由于指针造成的。 我试图从函数返回一个指针。 我试图返回的指针是在函数内部声明的,因此函数执行后就会被销毁。 有问题的代码在第 22-24 行被注释掉。

请随意嘲笑我的代码。

/**
*  Returns array of valid searches based on current coordinate
*/
void determine_searches(int row, int col, int last_row, int last_col, int *active_search){
    // define coordinate categories and related valid search directions
    int Library0[] = {2, 3, 4, -1};
    int Library1[] = {4, 5, 6, -1};
    int Library2[] = {2, 3, 4, 5, 6, -1};
    int Library3[] = {0, 1, 2, 3, 4, 5, 6, 7, -1};
    int Library4[] = {0, 1, 2, -1};
    int Library5[] = {0, 6, 7, -1};
    int Library6[] = {0, 1, 2, 6, 7, -1};
    int Library7[] = {0, 1, 2, 3, 4, -1};
    int Library8[] = {0, 4, 5, 6, 7, -1};

    int * Library[] = { 
        Library0, Library1, Library2,
        Library3, Library4, Library5,
        Library6, Library7, Library8,
    };

    // declare (and assign memory to) the array of valid search directions that will be returned
    //int *active_search;
    //active_search = (int *) malloc(SEARCH_DIRECTIONS * sizeof(int));


    // determine which is the correct array of search directions based on the current coordinate
    // top left corner
        int i = 0;
    if(row == 0 && col == 0){
        while(Library[0][i] != -1){
            active_search[i] = Library[0][i];
            i++;
        }
    }
    // top right corner
    else if(row == 0 && col == last_col){
        while(Library[1][i] != -1){
            active_search[i] = Library[1][i];
            i++;
        }
    }
    // non-edge columns of first row
    else if(row == 0 && (col != 0 || col != last_col)){
        while(Library[2][i] != -1){
            active_search[i] = Library[2][i];
            i++;
        }
    }
    // non-edge coordinates (no edge columns nor rows)
    else if(row != 0 && row != last_row && col != 0 && col != last_col){
        while(Library[3][i] != -1){
            active_search[i] = Library[3][i];
            i++;
        }
    }
    // bottom left corner
    else if(row == last_row && col == 0){
        while(Library[4][i] != -1){
            active_search[i] = Library[4][i];
            i++;
        }
    }
    // bottom right corner
    else if(row == last_row && col == last_col){
        while(Library[5][i] != -1){
            active_search[i] = Library[5][i];
            i++;
        }
    }
    // non-edge columns of last row
    else if(row == last_row && (col != 0 || col != last_col)){
        while(Library[6][i] != -1){
            active_search[i] = Library[6][i];
            i++;
        }
    }
    // non-edge rows of first column
    else if((row != 0 || row != last_row) && col == 0){
        while(Library[7][i] != -1){
            active_search[i] = Library[7][i];
            i++;
        }
    }
    // non-edge rows of last column
    else if((row != 0 || row != last_row) && col == last_col){
        while(Library[8][i] != -1){
            active_search[i] = Library[8][i];
            i++;
        }
    }
    active_search[i] = -1;
}

For my Programming 102 class we are asked to deliver C code that compiles and runs under Linux. I don't have enough spare space on my hard drive to install Linux alongside Windows, and so I use cygwin to compile my programs.

The most recent program I had to give in compiles and runs fine under cygwin. It compiles fine under Linux, but half-way through execution produces a segmentation fault. I explained this to the grad student who gives us class and he said that cygwin's version of GCC allows for sloppier code to be compiled and executed.

The few references I have found via google haven't been conclusive. One thread I found said that the cause for the seg fault under Linux is a memory leak. Why would this not affect the cygwin version?

I would use the University's computers, but I can't use Subversion on them which would significantly hinder my efforts. (I'm new to coding and often need to be able to be able to revert to X revisions ago).

Is cygwin's version of GCC really more 'lax' with the code it compiles? If so, are there any obvious issues to look out for when coding? Are there any alternatives for being able to write code that will run under Linux?

Edit

Thanks for the replies. I wasn't explicit enough in my original post: that there is a bug in my code was pretty much a given for me (I am quite new to programming, and really green when it comes to C, after all). My TA implied cygwin's GCC is a less reliable compiler -allowing for much sloppier code to run- than the one found under GNU/Linux. I found this strange and so had a search on the internet, but couldn't really find any references to that fact.

More than blaming the compiler vs. my code, I was wondering what the reason could be for the program to run under Windows and crash under Linux. The replies re: different memory managers and heap/stack layout under Windows/Linux were illustrating in that regard.

Would the conclusion that cygwin's GCC is just as 'good' as GNU/Linux', and it's the underlying operating systems/sheer luck that my buggy program runs under one and not the other be pretty much correct?

Regarding posting the source code, it's a homework assignment so I'd prefer to find the issue myself if at all possible :)

Edit 2

I've accepted jalf's answer as it talks about what makes the program run under Windows and not under Linux, which was what I really wanted to know. Thanks to everyone else who contributed, they were all very interesting and informative replies.

When I've found the issue and fixed it I'll upload a zip file with all the source code of this non-working version, in case anyone is curious to see what the hell I did :)

Edit 3

For those interested in seeing the code, I found the problem, and it was indeed due to pointers. I was trying to return a pointer from a function. The pointer I was trying to return was being declared inside the function and so was being destroyed once the function executed. Problematic code is commented out on lines 22-24.

Feel free to ridicule my code.

/**
*  Returns array of valid searches based on current coordinate
*/
void determine_searches(int row, int col, int last_row, int last_col, int *active_search){
    // define coordinate categories and related valid search directions
    int Library0[] = {2, 3, 4, -1};
    int Library1[] = {4, 5, 6, -1};
    int Library2[] = {2, 3, 4, 5, 6, -1};
    int Library3[] = {0, 1, 2, 3, 4, 5, 6, 7, -1};
    int Library4[] = {0, 1, 2, -1};
    int Library5[] = {0, 6, 7, -1};
    int Library6[] = {0, 1, 2, 6, 7, -1};
    int Library7[] = {0, 1, 2, 3, 4, -1};
    int Library8[] = {0, 4, 5, 6, 7, -1};

    int * Library[] = { 
        Library0, Library1, Library2,
        Library3, Library4, Library5,
        Library6, Library7, Library8,
    };

    // declare (and assign memory to) the array of valid search directions that will be returned
    //int *active_search;
    //active_search = (int *) malloc(SEARCH_DIRECTIONS * sizeof(int));


    // determine which is the correct array of search directions based on the current coordinate
    // top left corner
        int i = 0;
    if(row == 0 && col == 0){
        while(Library[0][i] != -1){
            active_search[i] = Library[0][i];
            i++;
        }
    }
    // top right corner
    else if(row == 0 && col == last_col){
        while(Library[1][i] != -1){
            active_search[i] = Library[1][i];
            i++;
        }
    }
    // non-edge columns of first row
    else if(row == 0 && (col != 0 || col != last_col)){
        while(Library[2][i] != -1){
            active_search[i] = Library[2][i];
            i++;
        }
    }
    // non-edge coordinates (no edge columns nor rows)
    else if(row != 0 && row != last_row && col != 0 && col != last_col){
        while(Library[3][i] != -1){
            active_search[i] = Library[3][i];
            i++;
        }
    }
    // bottom left corner
    else if(row == last_row && col == 0){
        while(Library[4][i] != -1){
            active_search[i] = Library[4][i];
            i++;
        }
    }
    // bottom right corner
    else if(row == last_row && col == last_col){
        while(Library[5][i] != -1){
            active_search[i] = Library[5][i];
            i++;
        }
    }
    // non-edge columns of last row
    else if(row == last_row && (col != 0 || col != last_col)){
        while(Library[6][i] != -1){
            active_search[i] = Library[6][i];
            i++;
        }
    }
    // non-edge rows of first column
    else if((row != 0 || row != last_row) && col == 0){
        while(Library[7][i] != -1){
            active_search[i] = Library[7][i];
            i++;
        }
    }
    // non-edge rows of last column
    else if((row != 0 || row != last_row) && col == last_col){
        while(Library[8][i] != -1){
            active_search[i] = Library[8][i];
            i++;
        }
    }
    active_search[i] = -1;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

失退 2024-07-20 13:53:19

就像其他人所说的那样,您可能想在此处发布一些代码,即使这不是您问题的真正要点。 让这里的每个人都仔细检查您的代码并看看他们是否能找到导致段错误的原因,这可能仍然是一个很好的学习经历。

但是,问题是,影响 C 程序的因素有很多依赖于平台的因素,而且基本上是随机的。 虚拟内存意味着有时,访问未分配的内存似乎是有效的,因为您访问了先前某个点分配的页面的未使用部分。 其他时候,它会出现段错误,因为您访问的页面根本没有分配给您的进程。 这确实是无法预测的。 这取决于您的内存分配位置,是在页面的边缘还是在中间? 这取决于操作系统和内存管理器,以及到目前为止已经分配了哪些页面,并且……您明白了。 不同的编译器、同一编译器的不同版本、不同的操作系统、系统上安装的不同软件、驱动程序或硬件,无论访问未分配的内存时是否出现段错误,任何事情都可能发生变化。

至于 TA 声称 cygwin 更“宽松”,那是一派胡言,原因很简单。
两个编译器都没有发现这个错误! 如果“本机”GCC 编译器确实不那么宽松,它会在编译时给出错误。 段错误不是由编译器生成的。 编译器无法做太多事情来确保您得到段错误而不是看起来可以工作的程序。

Like others have said, you might want to post some of your code here, even if that's not the real point of your question. It might still be a good learning experience to have everyone here poke through your code and see if they can find what caused the segfault.

But yeah, the problem is that there are so many platform-dependent, as well as basically random, factors influencing a C program. Virtual memory means that sometimes, accessing unallocated memory will seem to work, because you hit an unused part of a page that's been allocated at some earlier point. Other times, it'll segfault because you hit a page that hasn't been allocated to your process at all. And that is really impossible to predict. It depends on where your memory was allocated, was it at the edge of a page, or in the middle? That's up to the OS and the memory manager, and which pages have been allocated so far, and...... You get the idea. Different compilers, different versions of the same compilers, different OS'es, different software, drivers or hardware installed on the system, anything can change whether or not you get a segfault when you access unallocated memory.

As for the TA's claim that cygwin is more "lax", that's rubbish, for one simple reason.
Neither compiler caught the bug! If the "native" GCC compiler had truly been less lax, it would have given you an error at compile-time. Segfaults are not generated by the compiler. There's not much the compiler can do to ensure you get a segfault instead of a program that seemingly works.

情独悲 2024-07-20 13:53:19

我还没有听说过有关 Cygwin 下 GCC 怪异的任何具体信息,但就您而言,使用 gcc 的 -Wall 命令行选项来显示所有警告,看看它是否发现任何可能导致的问题可能是个好主意代码中的段错误。

I haven't heard of anything specific about GCC weirdness under Cygwin but in your case it would probably be a good idea to use the -Wall command-line option to gcc to show all warnings, to see if it finds anything that might be causing the segfault in your code.

水中月 2024-07-20 13:53:19

你的代码中肯定有一个错误。 Windows 内存管理器可能比 Linux 内存管理器更宽松。 在 Windows 上,您可能会用内存做坏事(例如覆盖数组边界、内存泄漏、双重释放等),但它会让您逃脱惩罚。 与此相关的著名故事可以在 http://www.joelonsoftware.com/articles/APIWar.html (搜索“SimCity”(有点长) ) 文章)。

You definitely have a bug somewhere in your code. It's possible that the Windows memory manager is being more lax than the Linux memory manager. On Windows, you might be doing bad things with memory (like overwriting array bounds, memory leaks, double-free'ing, etc.), but it's letting you get away with it. A famous story related to this can be found at http://www.joelonsoftware.com/articles/APIWar.html (search for "SimCity" on that (somewhat lengthy) article).

对你再特殊 2024-07-20 13:53:19

几乎可以肯定是指针错误或缓冲区溢出,可能是未初始化的变量。

未初始化的指针通常不会指向任何东西,但有时它会指向某些东西; 读取它或写入它通常会使程序崩溃,但也可能不会。

从释放的内存中进行写作或阅读是同一个故事; 你可能会侥幸逃脱,但也可能不会。

这些情况具体取决于堆栈、堆的布局方式以及运行时正在执行的操作。 很可能制作出一个在一个编译器/运行时组合上运行而不是在另一个编译器/运行时组合上运行的糟糕程序,仅仅是因为在一个编译器/运行时组合上它覆盖了一些无关紧要的东西(很多),或者未初始化的变量“碰巧”包含一个有效的变量。它所使用的上下文的值。

It's almost certainly a pointer error or buffer overrun, maybe an uninitialised variable.

An uninitialised pointer will usually point at nothing, but sometimes it will point at something; reading from it or writing to it will typically crash the program, but then again it MIGHT not.

Writing or reading from freed memory is the same story; you might get away with it, then again maybe not.

These situations depend on exactly how the stack, heap are laid out and what the runtime is doing. It is quite possible to make a bad program that works on one compiler / runtime combination and not another, simply because on one it overwrites something that doesn't matter (so much), or that an uninitialised variable "happens" to contain a valid value for the context it's used in.

旧梦荧光笔 2024-07-20 13:53:19

Cygwin 的 gcc 版本可能有其他默认标志和调整设置(例如 wchar_t 为 2 个字节),但我怀疑它的代码是否特别“宽松”,即便如此 - 你的代码不应该崩溃。 如果是这样,那么您的代码中很可能存在需要修复的错误。 例如,您的代码可能取决于 wchar_t 的特定大小,或者可能执行根本无法保证正常工作的代码,例如写入字符串文字。

如果你编写干净的代码,那么它也可以在 Linux 上运行。 我目前正在运行 Firefox 和 KDE 桌面,它们由数百万行 C++ 行组成,我没有看到这些应用程序崩溃:)

我建议您将代码粘贴到您的问题中,以便我们可以查看出了什么问题。

同时,您可以在 gdb 中运行您的程序,它是 Linux 的调试器。 您还可以在启用所有挡泥板检查和启用所有警告的情况下进行编译。 mudflaps 在运行时检查您的代码是否存在各种违规行为:

[js@HOST2 cpp]$ cat mudf.cpp
int main(void)
{
  int a[10];
  a[10] = 3;  // oops, off by one.
  return 0;
}
[js@HOST2 cpp]$ g++ -fmudflap -fstack-protector-all -lmudflap -Wall mudf.cpp
[js@HOST2 cpp]$ MUDFLAP_OPTIONS=-help ./a.out
  ... showing many options ...
[js@HOST2 cpp]$ ./a.out 
*******                 
mudflap violation 1 (check/write): time=1234225118.232529 ptr=0xbf98af84 size=44
pc=0xb7f6026d location=`mudf.cpp:4:12 (main)'                                   
      /usr/lib/libmudflap.so.0(__mf_check+0x3d) [0xb7f6026d]                    
      ./a.out(main+0xb9) [0x804892d]                                            
      /usr/lib/libmudflap.so.0(__wrap_main+0x4f) [0xb7f5fa5f]                   
Nearby object 1: checked region begins 0B into and ends 4B after                
mudflap object 0x9731f20: name=`mudf.cpp:3:11 (main) int a [10]'                
bounds=[0xbf98af84,0xbf98afab] size=40 area=stack check=0r/3w liveness=3        
alloc time=1234225118.232519 pc=0xb7f5f9fd                                      
number of nearby objects: 1                                                     
*** stack smashing detected ***: ./a.out terminated                             
======= Backtrace: =========
....

您可以执行许多 mudflap 检查,上面使用默认选项运行 a.out。 另一种有助于解决此类错误的工具是 valgrind,它也可以帮助您发现泄漏或通过一个错误来关闭,如上面所示。 将环境变量“MALLOC_CHECK_”设置为 1 也会打印违规消息。 有关该变量的其他可能值,请参阅 malloc 的联机帮助页。

要检查程序崩溃的位置,可以使用 gdb:

[js@HOST2 cpp]$ cat test.cpp
int main() {
    int *p = 0;
    *p = 0;
}
[js@HOST2 cpp]$ g++ -g3 -Wall test.cpp
[js@HOST2 cpp]$ gdb ./a.out
...
(gdb) r
Starting program: /home/js/cpp/a.out

Program received signal SIGSEGV, Segmentation fault.
0x080483df in main () at test.cpp:3
3           *p = 0;
(gdb) bt
#0  0x080483df in main () at test.cpp:3
(gdb)

使用 -g3 编译代码以包含许多调试信息,因此 gdb 可以帮助您找到程序崩溃的精确行。 所有上述技术同样适用于 C 和 C++。

Cygwin's version of gcc may have other default flags and tweaked settings (wchar_t being 2 bytes for example), but i doubt it is specifically more "lax" with code and even so - your code should not crash. If it does, then most probably there is a bug in your code that needs be fixed. For example your code may depend on a particular size of wchar_t or may execute code that's not guaranteed to work at all, like writing into string literals.

If you write clean code then it runs also on linux. I'm currently running firefox and the KDE desktop which together consist of millions of C++ lines, and i don't see those apps crashing :)

I recommend you to paste your code into your question, so we can look what is going wrong.

In the meantime, you can run your program in gdb, which is a debugger for linux. You can also compile with all mudflap checks enabled and with all warnings enabled. mudflaps checks your code at runtime for various violations:

[js@HOST2 cpp]$ cat mudf.cpp
int main(void)
{
  int a[10];
  a[10] = 3;  // oops, off by one.
  return 0;
}
[js@HOST2 cpp]$ g++ -fmudflap -fstack-protector-all -lmudflap -Wall mudf.cpp
[js@HOST2 cpp]$ MUDFLAP_OPTIONS=-help ./a.out
  ... showing many options ...
[js@HOST2 cpp]$ ./a.out 
*******                 
mudflap violation 1 (check/write): time=1234225118.232529 ptr=0xbf98af84 size=44
pc=0xb7f6026d location=`mudf.cpp:4:12 (main)'                                   
      /usr/lib/libmudflap.so.0(__mf_check+0x3d) [0xb7f6026d]                    
      ./a.out(main+0xb9) [0x804892d]                                            
      /usr/lib/libmudflap.so.0(__wrap_main+0x4f) [0xb7f5fa5f]                   
Nearby object 1: checked region begins 0B into and ends 4B after                
mudflap object 0x9731f20: name=`mudf.cpp:3:11 (main) int a [10]'                
bounds=[0xbf98af84,0xbf98afab] size=40 area=stack check=0r/3w liveness=3        
alloc time=1234225118.232519 pc=0xb7f5f9fd                                      
number of nearby objects: 1                                                     
*** stack smashing detected ***: ./a.out terminated                             
======= Backtrace: =========
....

There are many mudflap checks you can do, and the above runs a.out using the default options. Another tools which helps for those kind of bugs is valgrind, which can also help you find leaks or off by one bugs like above. Setting the environment variable "MALLOC_CHECK_" to 1 will print messages for violations too. See the manpage of malloc for other possible values for that variable.

For checking where your program crashes you can use gdb:

[js@HOST2 cpp]$ cat test.cpp
int main() {
    int *p = 0;
    *p = 0;
}
[js@HOST2 cpp]$ g++ -g3 -Wall test.cpp
[js@HOST2 cpp]$ gdb ./a.out
...
(gdb) r
Starting program: /home/js/cpp/a.out

Program received signal SIGSEGV, Segmentation fault.
0x080483df in main () at test.cpp:3
3           *p = 0;
(gdb) bt
#0  0x080483df in main () at test.cpp:3
(gdb)

Compile your code with -g3 to include many debugging information, so gdb can help you find the precise lines where your program is crashing. All the above techniques are equally applicable for C and C++.

时光暖心i 2024-07-20 13:53:19

GCC 的版本可能不是问题。 这更有可能是运行时库中的差异以及代码中的错误,而在针对 Windows 版本的运行时运行时,这些错误并未显现出来。 如果您想要更具体的答案,您可能需要发布段错误的代码和更多背景信息。

一般来说,最好在您将用于运行代码的环境下进行开发。

The version of GCC is probably not the issue. It's more likely to be a difference in the runtime library and a bug in your code that doesn't manifest itself when running against the Windows version of the runtime. You might want to post the code that segfaults and some more background information if you want a more specific answer.

In general, it's best to develop under the environment you're going to use for running your code.

剧终人散尽 2024-07-20 13:53:19

分段错误意味着您尝试访问无法访问的内存,这通常意味着您尝试取消引用空指针或双重删除内存或获得野指针。 有两个原因可能导致您在 cygwin 上表现良好,但在 Linux 上却表现不佳:要么是内存管理器的问题,要么您在其中一个方面比另一个更幸运。 几乎可以肯定您的代码有错误。

要解决此问题,请查看您的指针使用情况。 考虑用智能指针替换原始指针。 考虑搜索删除并立即将指针归零(尝试删除空指针是安全的)。 如果您可以破解 Linux,请尝试通过 gdb 获取堆栈跟踪,并查看发生的行是否有任何明显错误。 检查如何使用所有未初始化的指针。 如果您可以使用内存调试工具,请使用它。

A segmentation fault means that you tried to access memory you couldn't, which usually means you tried dereferencing a null pointer or you double-deleted memory or got a wild pointer. There's two reasons why you might have appeared to be fine on cygwin and not on Linux: either it was an issue with the memory managers, or you got more lucky on one of them than the other. It is almost certainly an error with your code.

To fix this, look at your pointer use. Consider substituting smart pointers for raw pointers. Consider doing a search for delete and zeroing the pointer immediately afterwards (it's safe to try to delete a null pointer). If you can get a crack at Linux, try getting a stack trace through gdb and see if there's anything obviously wrong at the line it happens. Examine how you use all pointers that aren't initialized. If you have access to a memory debugging tool, use it.

〃温暖了心ぐ 2024-07-20 13:53:19

Are you making any platform-specific assumptions, like the size of data types, data structure alignment in structs, or endianness?

风追烟花雨 2024-07-20 13:53:19

一些提示:

  1. 发布您的代码。 我敢打赌您会得到一些好的输入,使您成为更好的程序员。

  2. 使用-wall选项打开警告并纠正报告的任何问题。 同样,它可以帮助您成为一名更好的程序员。

  3. 使用调试器单步调试代码。 除了帮助您了解问题所在之外,它还将帮助您成为一名更好的程序员。

  4. 继续使用 Subversion 或其他源代码控制系统。

  5. 在确定已查明问题之前,切勿责怪编译器(或操作系统或硬件)。 即使如此,也要对自己的代码持怀疑态度。


Linux 上的 GCC 的源代码与 Cygwin 上的 GCC 相同。 由于 Cygwin POSIX 仿真层和底层 Windows API,平台之间存在差异。 额外的层可能比底层硬件更宽容,但这不能指望。

由于这是家庭作业,我认为发布代码是一个更好的主意。 还有什么比从专业程序员那里获取输入更好的学习方法呢? 不过,我建议您在附近的评论中注明您实施的任何建议。

Some hints:

  1. Post your code. I'll bet you will get some good input that will make you a better programmer.

  2. Turn on warnings with the -wall option and correct any problems that are reported. Again, it can help make you a better programmer.

  3. Step through the code with a debugger. Besides helping you understand where the problem is, it will help make you a better programmer.

  4. Continue to use Subversion or other source code control system.

  5. Never blame the compiler (or OS or hardware) until you are sure you've pinpointed the problem. Even then, be suspicious of your own code.


GCC on Linux is source-code identical to GCC on Cygwin. Differences between the platforms exist occur because of the Cygwin POSIX emulation layer and the underlying Windows API. It's possible the extra layers are more forgiving than the underlying hardware, but that's not be counted on.

Since it's homework, I'd say posting code is an even better idea. What better way to learn than getting input from professional programmers? I'd recommend crediting any suggestions you implement in nearby comments, however.

浅黛梨妆こ 2024-07-20 13:53:19

分段错误是访问不存在(或先前释放)地址的内存的结果。 我发现非常有趣的是,代码在 cygwin 下没有出现段错误。 这可能意味着您的程序使用了指向其他进程地址空间的野指针,并且实际上能够读取它(喘息),或者(更有可能)直到程序在 Linux 下运行时才到达实际导致段错误的代码。

我建议如下:

  1. 粘贴您的代码,因为这是一个非常有趣的问题
  2. 将其副本发送给 cygwin 开发人员
  3. 如果您需要编写更多在 Linux 下运行的程序,请获取便宜的 Linux VPS,这将使您的生活变得更加美好更轻松。

一旦您在 Linux 下工作(即进入您的 VPS),请尝试使用以下程序:

  • GDB
  • Valgrind
  • strace

另外,您可以尝试像 electric fence 这样的库来捕获程序运行时发生的此类事情。

最后,确保将 -Wall 传递给 gcc,您想要它传达的警告。

A segmentation fault is the result of accessing memory at a non-existent (or previously freed) address. What I find very interesting is that the code did NOT segfault under cygwin. That could mean that your program used a wild pointer to some other processes' address space and was actually able to read it (gasp), or (more likely) the code that actually caused the segfault was not reached until the program was run under Linux.

I recommend the following:

  1. Paste your code as it is a very interesting problem
  2. Send a copy of this to the cygwin developers
  3. Get a cheap Linux VPS if you'll be required to produce more programs that run under Linux, it will make your life much easier.

Once your working under Linux (i.e. shelled into your VPS), try working with the following programs:

  • GDB
  • Valgrind
  • strace

Also, you can try libraries like electric fence to catch these kinds of things as they happen while your program is running.

Finally, make sure -Wall is passed to gcc, you want the warnings it would convey.

撩起发的微风 2024-07-20 13:53:18

我不想听起来很粗鲁,但可能是你的代码不好,而不是编译器。 ;) 这样的问题实际上比您想象的更常见,因为不同的操作系统和编译器将采用不同的方式在堆栈和堆中组织应用程序的数据。 前者可能特别有问题,特别是如果您最终覆盖堆栈上的内存,或者引用系统决定用于其他用途的已释放内存。 所以基本上,有时你可能会侥幸逃脱,但有时你的应用程序会卡住并死掉。 无论哪种方式,如果它出现段错误,那是因为您试图引用不允许的内存,所以它在另一个系统/编译器下没有崩溃更像是一个“巧合”。

但实际上,段错误就是段错误,因此您应该调试代码以查找内存损坏,而不是调整编译器的配置来找出问题所在。

编辑:好的,我现在明白你的意思了...我以为你会带着“X 很糟糕,但 Y 工作得很好!”的想法来解决这个问题。 态度,但似乎是你的TA有这种态度。 ;)

无论如何,这里有一些调试问题的更多提示,例如:

  • 寻找指针算术,引用/取消引用可能的“doh!” 错误。 任何添加/减去一个(也称为栅栏错误)的地方都特别值得怀疑。
  • 注释掉问题区域周围对 malloc/free 的调用,以及使用这些指针的任何关联区域。 如果代码不再崩溃,那么您就朝着正确的方向前进了。
  • 假设您至少已经确定了代码崩溃的一般区域,请在其中插入早期的 return 语句并找到代码不会崩溃的点。 这可以帮助找到该点和代码实际崩溃位置之间的某个区域。 请记住,像这样的段错误不一定直接发生在错误所在的代码行。
  • 使用系统上可用的内存调试工具。
    • 在 Unix 上,请查看本关于在 Unix 上调试内存的指南,以及valgrind 分析器(@Sol,感谢提醒我这一点)
    • 在 Visual Studio/Windows 上,您的好伙伴CrtCheckMemory() 非常方便。 另外,请阅读 CRT 内存调试模式,因为它们是其中之一在 VS 中工作的更好的功能。 很多时候,一旦您记住了各种模式,只需在 VS 中打开一个内存选项卡就足以诊断此类错误。
    • 在 Mac OSX 中,您可以在 malloc_error_break(来自 gdb 或 Xcode)上设置断点,这会导致调试器在 malloc 检测到内存损坏时中断。 我不确定这是否在其他 UNIX 版本中可用,但快速谷歌搜索似乎表明它仅适用于 Mac。 另外,valgrind 似乎在 OSX 上存在,看起来相当“实验”。

I don't mean to sound rude, but it's probably your code that's bad, not the compiler. ;) Problems like this are actually more common than you'd think, because different OS's and compilers will have different ways of organizing your application's data in the stack and heap. The former can be particularly problematic, especially if you end up overwriting memory on the stack, or referencing freed memory which the system has decided to use for something else. So basically, you might get away with it sometimes, but other times your app will choke and die. Either way, if it segfaults, it's because you tried to reference memory which you were not allowed, so it's more of a "happy coincidence" that it didn't crash under another system/compiler.

But really, a segfault is a segfault, so you should instead debug your code looking for memory corruption instead of tweaking the compiler's configuration to figure out what's going wrong.

Edit: Ok, I see what you mean now... I thought you were coming at this problem with an "X sucks, but Y works just fine!" attitude, but it seems to be your TA who's got that. ;)

Anyways, here's some more hints for debugging problems like this:

  • Look for pointer arithmetic, referencing/dereferencing for possible "doh!" errors. Any place where you are adding/subtracting one (aka, fencepost errors) are particularly suspect.
  • Comment out calls to malloc/free around the problem area, and any associated areas where those pointers are used. If the code stops crashing, then you're headed in the right direction.
  • Assuming you've at least identified the general area where your code is crashing, insert early return statements in there and find the point where your code doesn't crash. This can help to find an area somewhere between that point and where your code actually crashes. Remember, a segfault like this may not necessarily happen directly at the line of code where your bug is.
  • Use the memory debugging tools available on your system.
    • On Unix, check out this guide for debugging memory on unix, and the valgrind profiler (@Sol, thx for reminding me about this one)
    • On Visual Studio/Windows, your good 'ol buddy CrtCheckMemory() comes in rather handy. Also, read up on the CRT memory debugging patterns, as they're one of the nicer features of working in VS. Often times, just leaving open a memory tab in VS is enough to diagnose bugs like this once you memorize the various patterns.
    • In Mac OSX, you can set a breakpoint on malloc_error_break (either from gdb or Xcode), which causes it the debugger to break whenever malloc detects memory corruption. I'm not sure whether that's available in other unix flavors, but a quick google search seems to indicate it's mac-only. Also, a rather "experimental" looking version of valgrind seems to exist for OSX.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文