【问题标题】:printf %f Segmentation faultprintf %f 分段错误
【发布时间】:2012-06-26 15:13:56
【问题描述】:

我在函数中有这段代码。我想在这里打印y的值。

if (x1 < 0 || y1 < 0) {

    // Vertical lign outside of layer
    if (dx == 0 && y1 < 0) {
        return GKIT_NOERR;
    }

    float m = dy / dx;
    float t = y1 - m * x1;
    float x = -t / m;
    float y = m * x + t;

    printf("Hello %s. You are %f years old.\n", "Niklas", y);
}

但是我遇到了分段错误。它完全可以与 no 值一起打印为浮点数。我可以将其更改为 %d 或类似名称,效果很好。

    int val = (int) y;
    printf("Hello %s. You are %d years old.\n", "Niklas", val);

知道 Segfault 来自哪里吗?

编辑:完成功能。

// coding: ascii
// author: Niklas Rosenstein
// e-mail: rosensteinniklas@googlemail.com

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gkit/defines.h"
#include "gkit/utils.h"
#include "gkit/graphicslayer.h"

#define SWAP_IF_NECCESSARY(x1, y1, x2, y2)  \
    if (x2 < x1 && y2 < y1) {               \
        int temp = x2;                      \
        x2 = x1;                            \
        x1 = temp;                          \
        temp = y2;                          \
        y2 = y1;                            \
        y1 = temp;                          \
    }

/* Based on Bresenhams line algorithm. */
int gk_GraphicsLayer_drawLine(gk_GraphicsLayer* layer, gk_Color* color,
                              int x1, int y1, int x2, int y2,
                              gk_ColorBlendProc blend, gk_float opacity) {
    SWAP_IF_NECCESSARY(x1, y1, x2, y2);

    float dx = x2 - x1;
    float dy = y2 - y1;
    float cx = x1;
    float cy = y1;

    // Figure out where to start in case x1 or y1 are outside of the layer.
    if (x1 < 0 || y1 < 0) {

        // Vertical lign outside of layer
        if (dx == 0 && y1 < 0) {
            return GKIT_NOERR;
        }

        // The function's slope (m)
        // ------------------------
        float m = dy / dx;


        // Find the y-axis intersection (t)
        // -------------------------------
        // y = mx + t   =>
        // y - mx = t

        float t = y1 - m * x1;

        // Compute the root of the function (N)
        // ------------------------------------
        // 0 = mx + t   =>
        // mx = -t      =>
        // x = -t / m

        float x = -t / m;
        float y = m * x + t;

        printf("Hello %s. You are %f years old.\n", "Niklas", y);
    }


    int incx = GKIT_SIGNUM(dx);
    int incy = GKIT_SIGNUM(dy);
    if (dx < 0) { dx = -dx; }
    if (dy < 0) { dy = -dy; }

    int pdx, pdy;
    int ddx, ddy;
    int es, el;

    ddx = incx;
    ddy = incy;

    if (dx > dy) {
        pdx = incx;
        pdy = 0;
        es = dy;
        el = dx;
    }
    else {
        pdx = 0;
        pdy = incy;
        es = dx;
        el = dy;
    }

    float err = el / 2.0;

    #define SET_PIXEL(x, y) \
        do { \
        gk_Color* c = GKIT_GRAPHICSLAYER_ACCESSPIXEL(layer, (int)x, (int)y); \
        if (blend != Null) {                \
            gk_Color t = *c;                \
            blend(color, &t, c, opacity);   \
        }                                   \
        else {                              \
            *c = *color;                    \
        } } while (0)

    SET_PIXEL(cx, cy);

    int t;
    for (t=0; t < el; t++) {
        err -= es;
        if (err < 0) {
            err += el;
            cx += ddx;
            cy += ddy;
        }
        else {
            cx += pdx;
            cy += pdy;
        }
        SET_PIXEL(cx, cy);
    }

    #undef SET_PIXEL

    return GKIT_NOERR;
}

编辑:完整的堆栈跟踪:

#0 0xb7e68cb0   ___printf_fp(fp=0xb7fc3a20, info=0xbffff684, args=0xbffff6f8) (printf_fp.c:844)
#1 0xb7e63ab0   _IO_vfprintf_internal(s=0xb7fc3a20, format=<optimized out>, ap=0xbffff750 "\001") (vfprintf.c:1623)
#2 0xb7e6cc2f   __printf(format=0x8049da0 "Hello %s. You are %f years old.\n") (printf.c:35)
#3 0x8049143    gk_GraphicsLayer_drawLine(layer=0x804d008, color=0xbffff810, x1=-20, y1=-10, x2=49, y2=200, blend=0, opacity=0) (/home/niklas/git/c-gkit/gkit/graphicslayer.c:180)
#4 0x8049ba4    test_drawLine() (/home/niklas/git/c-gkit/main.c:46)
#5 0x8049c80    main() (/home/niklas/git/c-gkit/main.c:68)

编辑:请注意printf()确实在将它放在 if 子句之后或之前时起作用。 IE。类似的东西

    printf("Foo: %f\n", 1.0);
    // Figure out where to start in case x1 or y1 are outside of the layer.
    if (x1 < 0 || y1 < 0) {

        // Vertical lign outside of layer
        if (dx == 0 && y1 < 0) {
            return GKIT_NOERR;
        }

确实有效,但将printf() 移入 if 子句会产生分段错误。

更新:根据T.E.D.的回答,我已经测试了一下,结果如下:

问题似乎是比较操作的结果 (&lt;)。我可以的

if (True) { printf("%f", 53.3); }

但我做不到

if (x1 < 0 || y1 < 0) { printf("%f", 53.3); }
// nor
if (x1 < 0) { printf("%f", 53.3); }
// nor
int x_smaller = x1 < 0;
if (x_smaller) { printf("%f", 53.3); }

有趣的是,这是可行的:

int x_smaller = x1 < 0;
int y_smaller = y1 < 0;
x_smaller = y_smaller = 1;
if (x_smaller || y_smaller) { printf("%f", 53.3); }

结论:在 if 子句中测试的操作 x1 &lt; 0y1 &lt; 0 的结果使 printf() 失败。问题是:

  1. 大富奇?为什么会这样?
  2. 我该如何解决?

如果您对整个代码感兴趣,我不介意分享它。它在github 上。这是一个 Code::Blocks 项目。唯一的包含路径必须是 gkit 文件夹的父目录。

【问题讨论】:

  • 是否有完整的代码(即包括main() 和所有#includes)来测试?
  • 它是我正在编写的库的一部分,并且依赖于它的许多内容。我当然可以发布代码,它基本上是 Bresenham 算法的一部分,上面的代码应该找出在给定点位于绘图区域之外的情况下从哪里开始行。
  • 您是否通过检查堆栈跟踪确定了段错误发生的位置?很有可能它发生在这个 printf 之后。
  • @WilliamPursell 好吧,当给定点 位于 绘图区域之外时,它给出了段错误。这就是为什么我在我的代码中第一个代码的 if 子句末尾创建了一个 return GKIT_NOERR (所以当 if 子句运行良好时它不会崩溃)。其次,查看编辑。
  • @NiklasR “完成”功能确实有帮助。如果没有所需的标头,代码将无法编译,并且没有main() 可以调用gk_GraphicsLayer_drawLine()

标签: c segmentation-fault printf stdio


【解决方案1】:

这正是我讨厌printf() 的原因。它是在其他容易出错的语言中最容易出错的例程。

处理“奇怪”崩溃的第一件事是简化逻辑以尝试缩小范围。

在这种情况下,接下来我会尝试在 printf 之前将您的浮点数设置为已知值(例如:1.0)。可能是你的printf 有一个错误,你碰巧在那里有一些奇怪的值。

如果可行(打印1.0),那么我的下一步是尝试打印该变量中的位。对于 C,这可能会将格式更改为 %x 并将参数更改为 *((unsigned int *)(&amp;y))

如果它不起作用(我猜不是您的评论),请继续简化。尝试删除%s 及其参数(无论如何都是一种不必要的ATM)。如果仍然失败,请尝试:

  • 将损坏的代码 sn-p 移动到独立的“main”中,然后(假设它有效)添加代码直到它损坏。
  • 从现有代码中注释掉代码,直到找到可以使其工作的内容。

【讨论】:

  • 应该printf("Hello %s. You are %f years old.\n", "Niklas", 1.0); 使用您的方法吗?因为它不... 使%d 起作用。 ._.'啊,已经忘记告诉printf 在另一个上下文中工作。 IE。在 if 子句之外。应该添加..
  • 我敢打赌,printf 本身在这里完全是无辜的,堆栈必须被打破。
  • @unkulunkulu - 我现在也怀疑了。在我的回答中执行任一项目符号应该有助于查明罪魁祸首。
  • @T.E.D.,对,在问题本身的 cmets 中执行该操作。
  • 如果您不太了解该语言,则该语言不容易出错。不然。不要责怪语言。责备它的滥用。
【解决方案2】:

感谢 unkulunkulu,他在chat 中提供了帮助,我们得以找到问题所在。

我无法相信之前对gk_GraphicsLayer_drawLine 的调用会影响后续调用的行为,但this 正是如此。在我的main() 函数中,我调用了该函数三遍。第一次调用意外收到的值也超出了gk_GraphicsLayer 的像素数组的范围。第三个调用最终导致程序崩溃。

这也解释了为什么在 if-clause(错误出现的地方)修复了段错误之后退出函数。这是因为它阻止了函数访问它不应该访问的内存。

总结:写入无效地址的内存非常危险,它甚至会触发一个完全其他的函数失败并导致您错误假设。不幸的是,当无效地址仍在操作系统为您的应用程序提供的内存范围内时,不会收到分段错误错误。

【讨论】:

  • 是的,但仅在发布答案后 2 天。
猜你喜欢
  • 2013-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-27
  • 1970-01-01
  • 2012-03-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多