修复并不容易,C语言优先级的问题。
The fix wasn't easy, or C precedence bites

原始链接: https://boston.conman.org/2025/10/20.1

## Mod_blog 进行万圣节清理 历经十年的圣诞节发布(偶有例外),mod_blog 软件的最新更新提前到来——正值万圣节!这次发布不同寻常,因为它*删除了*长期存在的特性,作者承认最初这个决定让他感到害怕。 更新的核心源于修复 URL 解码函数中的一个错误。然而,C 语言运算符优先级中的一个微妙错误引入了一个新的、难以发现的错误,由于作者不经常使用 Web 界面,这个错误一直未被察觉。最终,超过 3000 行代码被删除,包括自动社交媒体更新和段落格式化选项等过时功能。 饱受垃圾邮件困扰的电子邮件通知也进行了改进,以利用更新的钩子机制,为剩余的三位用户保留服务。虽然删除既定功能令人望而却步,但作者认为这是朝着更精简、更易于维护的代码库迈出的积极一步。

## 黑客新闻讨论:C 优先级与代码风格 一篇黑客新闻帖子讨论了 conman.org 上的一个 bug 修复,并引发了关于 C 代码风格和潜在陷阱的争论。核心问题源于优先级问题——`*foo + 1` 被解释为 `(*foo) + 1`,很容易通过使用括号来避免。 评论员普遍批评了原始代码的可读性,指出过于简洁的指针运算(例如,使用 `*(src+1)` 而不是 `src[1]`),不寻常的格式(例如,单语句 `if` 块),以及在 C 中对 `CppStyleFunctionNames()` 的特殊用法。 讨论延伸到编码风格的历史,指出 Pascal 等语言的影响,以及某些约定在非 UNIX 系统(MS-DOS、Amiga 等)上的流行。`clang-format` 和 `GNU indent` 等工具被提及为自动格式化的潜在解决方案,但承认了将它们应用于大型代码库的挑战。 最终,共识倾向于优先考虑清晰度,并避免依赖复杂的优先级规则,即使这意味着代码会稍长。 许多评论员强调了使用括号来明确定义运算顺序的重要性。
相关文章

原文

The fix wasn't easy, or C precedence bites

For the past decade now, I've done a Christmas release for mod_blog (only missing the years 2019 and 2023), just beacuse. I was poking around the codebase looking for changes I could make for Christmas this year, and well, I got a bit impatient and have just now released a version in time for Halloween. And it's scary—I'm removing features!

I've removed features in the past, like no longer supporting “ping servers” when it became clear it wasn't worth it, or automatically updating Linked­Tik­Face­My­Insta­Pin­Me­Gram­We­Tok­In­Book­Space­Trest when Insta­Pin­Tik­My­Linked­Face­Me­Trest­Book­Gram­We­In­Space­Tok changed how it works often enough to make it annoying for me to continue. But this time … this time it's different. This is removing functionality that has existed in the code base since the beginning!

To make it easier to write entries, I had code within mod_blog to process the input—mostly what existed was to convert sequences like ``quoted'' to “quoted” and “...” to “…”, but with an option to add <P> tags around logical paragraphs. But given that I now use my own markup language, I rarely used the web interface (like, I can count on my fingers the number of times I've used it and still have a few left over should give an indication of how little I use it) and the code just sat there, unused. So unused that in fixing one bug I introduced another bug in the code I fixed!

To recap, here's the original code:

char UrlDecodeChar(char **psrc)
{
  char *src;
  char  c;
  
  assert(psrc  != NULL);
  assert(*psrc != NULL);
  
  src = *psrc;
  c   = *src++;
  if (c == '+')
    c = ' ';
  else if (c == '%')
  {
    assert(isxdigit(*src));
    assert(isxdigit(*(src+1)));
    c    = ctohex(*src) * 16 + ctohex(*(src+1));
    src += 2;
  }
  *psrc = src;
  return(c);
}

and the “fixed” version:

char UrlDecodeChar(char **psrc)
{
  char *src;
  char  c;
  
  assert(psrc  != NULL);
  assert(*psrc != NULL);
  
  src = *psrc;
  c   = *src++;
  if (c == '+')
    c = ' ';
  else if (c == '%')
  {
    if (!isxdigit(*src))   return '\0';
    if (!isxdigit(*src+1)) return '\0';
    c    = ctohex(*src) * 16 + ctohex(*(src+1));
    src += 2;
  }
  *psrc = src;
  return(c);
}

I don't fault you if you can't spot the bug. I only found it when testing the web interface to ensure it wasn't completely broken with the conversion code removed (instead it's now only mostly broken but that's an interesting case in and of itself and requires its own post). The bug is in this line of code:

if (!isxdigit(*src+1)) return '\0';

The issue is due to C's precedence rules and dereferencing rules. The code above is parsed as src[0] + 1 instead of the src[1] that I was intending. When I modified the function, changing the calls to assert() into actual code to return an error (I typed in the new code as that's faster than modifying the existing code) I … kind of missed that.

Oh, who am I kidding? I totally missed that. But because I don't use the web interface this bug went unnoticed. Sigh.

For the record, I changed the code to read:

if (!isxdigit(src[0])) return '\0';
if (!isxdigit(src[1])) return '\0';
c    = ctohex(src[0]) * 16 + ctohex(src[1]);

Another long time feature I've removed is email notification. I added it early on where you could submit your email address to get notified of posts, but spammers and a lack of outside interest pretty much put the kibosh on that. As I still have three users of the email notification (one is me, one is Bunny, and one is one other person whom I'm not sure still reads the emails but they haven't bounced yet) I don't want to drop support completely, so now the email notifications are sent via the hook mechanism I added a few years ago.

In total, I removed over 3,000 lines of code from mod_blog. Granted, over 2,000 of them were in one function that was removed, but still, it's 3,000 lines of code I don't have to worry about any more.

Still, it's a bit scary to remove features that have been there for so long, and thus, a Halloween release.

You have my permission to link freely to any entry here. Go ahead, I won't bite. I promise.

The dates are the permanent links to that day's entries (or entry, if there is only one entry). The titles are the permanent links to that entry only. The format for the links are simple: Start with the base link for this site: https://boston.conman.org/, then add the date you are interested in, say 2000/08/01, so that would make the final URL:

https://boston.conman.org/2000/08/01

You can also specify the entire month by leaving off the day portion. You can even select an arbitrary portion of time.

You may also note subtle shading of the links and that's intentional: the “closer” the link is (relative to the page) the “brighter” it appears. It's an experiment in using color shading to denote the distance a link is from here. If you don't notice it, don't worry; it's not all that important.

It is assumed that every brand name, slogan, corporate name, symbol, design element, et cetera mentioned in these pages is a protected and/or trademarked entity, the sole property of its owner(s), and acknowledgement of this status is implied.

联系我们 contact @ memedata.com