3

このコードは関数に含まれています。ここの値を出力したい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);
}

しかし、セグメンテーション違反が発生します。フロートとして出力されるのは、まったく値なしで機能します。私はそれを%dまたは同様のものに変更することができます、それはうまくいきます。

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

セグメンテーション違反がどこから来たのか考えていますか?

編集:完全な機能。

// 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)

編集: if句の前後に配置すると機能することに注意してくださいprintf() つまり、

    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;
        }

は機能しますが、if句のprintf() 内側を移動すると、セグメンテーション違反が発生します。

更新TEDの回答によると、私は少しテストしましたが、これが出てきたものです:

問題は、比較操作の結果であるように思われます(<)。できます

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 < 0結果は失敗します。質問は次のとおりです。y1 < 0printf()

  1. DAFUQ?なぜこうなった?
  2. どうすれば修正できますか?

コード全体に興味がある場合は、共有してもかまいません。githubにあります。これはCode::Blocksプロジェクトです。gkit唯一のinclude-pathは、フォルダの親ディレクトリへのパスである必要があります。

4

2 に答える 2

3

これがまさに私が嫌いな理由ですprintf()。これは、エラーが発生しやすい言語で最もエラーが発生しやすいルーチンです。

「werid」クラッシュで最初に行うことは、ロジックを単純化して絞り込もうとすることです。

この場合、次に、フロートを既知の値(例1.0:)の直前に設定してみますprintfprintfそこにたまたまある奇妙な値にバグがある可能性があります。

それが機能する(印刷する1.0)場合、次のステップはその変数のビットを印刷しようとすることです。Cの場合、おそらくフォーマットをに変更し%x、パラメータを次のように変更します。*((unsigned int *)(&y))

それがうまくいかなかった場合(私はあなたのコメントからではないと推測しています)、単純化し続けてください。とそのパラメータを削除してみてください%s(とにかく不必要なATMの一種)。それでも失敗する場合は、次のいずれかを試してください。

  • 壊れたコードスニペットをスタンドアロンの「メイン」に移動し、(機能すると仮定して)壊れてしまうまでコードを追加します。
  • それを機能させる何かが見つかるまで、既存のコードからコードをコメントアウトします。
于 2012-06-26T15:29:46.650 に答える
2

チャットで助けてくれたunkulunkuluのおかげで、問題を見つけることができました。

gk_GraphicsLayer_drawLine以前のへの呼び出しが後続の呼び出しの動作に影響を与える可能性があるとは信じられませんでしたが、まさにその通りでした。私のmain()関数では、関数を3回呼び出しました。最初の呼び出しは、のピクセル配列の範囲外にも到達した値を誤って受信しましたgk_GraphicsLayer。3番目の呼び出しは、最終的にプログラムをクラッシュさせた呼び出しでした。

これは、 if句(エラーが発生した場所)の後で関数を終了すると、セグメンテーション違反が修正された理由も説明しています。これは、関数がアクセスしてはならないメモリにアクセスできなかったためです。

要約:無効なアドレスのメモリへの書き込みは非常に危険であり、完全に他の関数をトリガーして失敗し、誤解を招く可能性さえあります。残念ながら、無効なアドレスがOSによってアプリケーションに提供されたメモリの範囲内にある場合、セグメンテーション違反エラーは発生しません。

于 2012-06-26T21:09:13.687 に答える