Reminder: Don’t Hard Code It

Today’s reminder comes from the “magic number” department, where we remind you to never hard-code a magic number in your software. For example, the value for ETIMEDOUT on Linux can vary depending on your C library. glibc, for example, defines it as 110, but uClibc defines it as 145. This tends to matter when you are using a return value from, for example, libusb, at an important branching point in your software. Of course, this whole exercise is hypothetical. I would never hard code a number like that, of course not.

The upside:
The libusb source code is available for the world to see.

The downside:
The libusb documentation makes no mention of ETIMEDOUT.

7 comments to “Reminder: Don’t Hard Code It”

You can leave a reply or Trackback this post.
  1. I’m a little curious where that 145 is coming from. On two of my systems (x86-archlinux and armel-debian), ETIMEDOUT is defined in /usr/include/asm-generic/errno.h.

    Here’s the package on x86-archlinux:
    % pacman -Qo /usr/include/asm-generic/errno.h
    /usr/include/asm-generic/errno.h is owned by linux-api-headers 2.6.33.1-1

    And here’s the package on armel-debian:
    $ dpkg -S /usr/include/asm-generic/errno.h
    linux-libc-dev: /usr/include/asm-generic/errno.h
    $ apt-cache show linux-libc-dev | grep ^Source:
    Source: linux-2.6

    I don’t see ETIMEDOUT defined anywhere in uClibc.

    The only place on my system where I see ETIMEDOUT defined to 145 is in /usr/include/mysql/my_pthread.h, but that’s only when __WIN__ is defined.

    Do you have some odd kernel headers in your cross compilation environment?

  2. Byron,

    It’s possible. I’m using OpenWrt/BuildRoot with uClibc. I’ll check it out.

    –Dave

  3. Okay, Byron, check out this tiny C program:

    #include <stdio.h>
    #include <errno.h>
    
    int main()
    {
        printf("ETIMEDOUT: %d\n", ETIMEDOUT);
    }
    

    When I run it on Ubuntu and OpenSuse 11.0 (both using glibc), it prints:

    ETIMEDOUT: 110

    But when I run it on OpenWrt/uClibc, it prints:

    ETIMEDOUT: 145

    I don’t know where it’s defined, but it definitely looks different to me. What’s your take?

  4. Here’s an easy way to find where the definition comes from. Just add this line before main() in your test program:

    #define ETIMEDOUT 999

    When you build, gcc should spit out a nice error like this one:

    etimedout.c:4:1: warning: “ETIMEDOUT” redefined
    In file included from /usr/include/asm/errno.h:1,
    from /usr/include/linux/errno.h:4,
    from /usr/include/bits/errno.h:25,
    from /usr/include/errno.h:36,
    from etimedout.c:2:
    /usr/include/asm-generic/errno.h:83:1: warning: this is the location of the previous definition

    Do you check for ETIMEDOUT as a return value somewhere in your code? I ask because it looks like libusb only checks for it once and uses ETIMEDOUT as a constant, so it shouldn’t matter what the value is unless it was different when your buildroot for OpenWrt was created.

  5. Okay, looks like it’s defined here on OpenWrt:

    staging_dir/toolchain-mips_r2_gcc-4.3.3+cs_uClibc-0.9.30.1/mips-openwrt-linux-uclibc/sys-include/errno.h:98

       #define ETIMEDOUT 145

    And here on Ubuntu:

    /usr/include/asm-generic/errno.h:83

       #define ETIMEDOUT 110
  6. P.S. I’m using gcc 4.4.1 on Ubuntu, not sure of the libc version.

  7. By the way, the only reason I used a hard-coded 110 in my code was because I hadn’t read the libusb code to know what it was returning. I had searched their documentation trying to figure out what values to expect, but could find no reference to ETIMEDOUT. When I ported my app to OpenWrt/uClibc, that’s when I realized that libusb was returning something different (145 it turnd out), and only then did I read their code to figure out just what symbol that was. So yes, in short, I was checking for that as a libusb return value (from usb_bulk_read() actually), and after I discovered that libusb uses ETIMEDOUT, I changed my code to also check for ETIMEDOUT rather than 110.