Reminder: Don’t Hard Code It
April 6th, 2010Today’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.
April 7th, 2010 at 9:21 am
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?
April 7th, 2010 at 9:34 am
Byron,
It’s possible. I’m using OpenWrt/BuildRoot with uClibc. I’ll check it out.
–Dave
April 8th, 2010 at 11:37 pm
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?
April 9th, 2010 at 6:13 am
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.
April 9th, 2010 at 8:01 am
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
And here on Ubuntu:
/usr/include/asm-generic/errno.h:83
April 9th, 2010 at 8:03 am
P.S. I’m using gcc 4.4.1 on Ubuntu, not sure of the libc version.
April 10th, 2010 at 9:18 pm
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.