我在一个函数中有这段代码。我想在这里打印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 " 01") (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子句之后或之前时确实有效。 即类似的东西
printf("Foo: %fn", 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()
会产生分段错误。
更新:根据T.E.D.'的答案,我已经测试了一下,结果是这样的:
问题似乎是比较操作的结果(<
)。我能做到
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 < 0
测试的操作的结果使printf()
失败。问题是:
- 达福克?为什么会这样?
- 我该如何解决它?
如果您对整个代码感兴趣,我不介意分享它。它在github上。这是一个代码::块项目。唯一的包含路径必须是 gkit
文件夹的父目录。
我讨厌printf()
的原因。它是关于在其他容易出错的语言中最容易出错的例程。
对于"怪异"崩溃,首先要做的是简化逻辑以尝试缩小范围。
在这种情况下,我接下来会尝试将您的浮点数设置为已知值(例如:1.0
),就在printf
之前。可能是你的printf
有一个关于你碰巧在那里的一些奇怪值的错误。
如果这有效(打印1.0
),那么我的下一步将是尝试打印该变量中的位。对于 C,这可能是将格式更改为 %x
并将参数更改为类似 *((unsigned int *)(&y))
如果它不起作用(我猜不是来自您的评论)请继续简化。尝试删除%s
及其参数(无论如何,有点不合时宜的ATM)。如果仍然失败,请尝试:
- 将损坏的代码片段移动到独立的"main"中,然后(假设它有效)添加代码,直到它中断。
- 从现有代码中注释掉代码,直到找到使其工作的内容。
感谢在聊天中提供帮助的unkulunkulu,我们能够找到问题。
我不敢相信以前对gk_GraphicsLayer_drawLine
的调用会影响后续调用的行为,但事实确实如此。在我的main()
函数中,我调用了该函数三次。第一次调用意外地收到了值,这些值也超出了gk_GraphicsLayer
像素数组的范围。第三个电话是最终使程序崩溃的电话。
这也解释了为什么在 if 子句(错误出现的位置)之后退出函数可以修复段错误。这是因为它阻止了函数访问它不应该访问的内存。
总结:写入无效地址的内存非常危险,它甚至可能触发一个完全不同的函数失败并导致您错误假设。遗憾的是,当无效地址仍在操作系统为应用程序提供的内存范围内时,不会收到分段错误错误。