简体   繁体   中英

printf %f Segmentation fault

I have this piece of code in a function. I want to print the value of y here.

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

But I get a segmentation fault. It works with no value at all to be printed as float. I can change that to %d or similar, which works fine.

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

Any idea where the Segfault comes from?

Edit : Complete function.

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

Edit : Complete stack trace:

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

Edit : Please note that printf() does work when putting it after or before the if-clause. Ie Something like

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

does work , but moving the printf() inside the if-clause yields a segmentation fault.

Update : According to TED 's answer, I've tested around a little and this is what came out:

The problem seem the be the outcome of the comparison operations ( < ). I can do

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

but I can't do

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

Interesting is, that this works:

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

Conclusion : The outcome of the operations x1 < 0 and y1 < 0 tested in the if-clause make printf() fail. The questions are:

  1. DAFUQ? Why is this happening?
  2. How can I fix it?

If you are interested in the whole code, I don't mind sharing it. It's on github . It's a Code::Blocks project. The only include-path must be to the parent-directory of the gkit folder.

This is exactly why I hate printf() . It is about the most error-prone routine in an otherwise error-prone language.

The first thing to do with a "werid" crash is to simplify the logic to try to narrow it down.

In this case, I'd next try setting your float to a known value (eg: 1.0 ) right before the printf . It could be that your printf has a bug on some weird value that you happen to have in there.

If that works (prints 1.0 ) then my next step would be to try to print the bits in that variable. For C, that would probably be changing the format to %x and the parameter to something like *((unsigned int *)(&y))

If it didn't work (I'm guessing not from your comment) keep simplifying. Try removing the %s and its parameter (kind of unnessecary ATM anyway). If that still fails, either try:

  • moving your broken code snippet into a stand-alone "main" and then (assuming it works) add in code until it breaks.
  • commenting out code from your existing code until you find something that makes it work.

Thanks to unkulunkulu, who provided his help in the chat , we were able to find the issue.

I couldn't believe that previous calls to gk_GraphicsLayer_drawLine could influence the behaviour of following calls, but exactly this was the case. In my main() function, I called the function three times. The first call recieved accidently values that did also reach out of bounds of the pixel-array of gk_GraphicsLayer . The third call was the one who finally crashed the program.

This also explains why exiting the function after the if-clause (where the error appeared in) fixed the segfault. It was because it prevented the function from accessing memory it shouldn't access.

Summary : Writing to the memory of an invalid address is so much dangerous, it can even trigger a completely other function to fail and lead you to miss-asumptions. Unfortunately, one doesn't recieve Segmentation Fault errors when the invalid address is still in range of the memory that was supplied by the OS for your application.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM