Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

This is a discussion that has happened here before and has generated its share of sparks, but I'll risk it :-). It is hardly a problem in the context of a userspace TCP/IP stack (I don't think Linux runs on any machine with non 8-bit bytes); it's just a good illustration about the kind of pitfalls that programming at this level sometimes poses.

I would suggest being a little more careful with this:

> unsigned char dmac[6];

because there are several platforms, all of them high-performance, non-legacy processors, where unsigned char is not 8 bits :-). E.g. on AD's SHARC, it's 32. You're declaring the struct with __attribute__((packed)), so I assume you're going to want to fill it automatically through DMA at some point in the future. On such a platform, it won't have the expected results. A colleague got bit by this, on a device that's sitting on my desk right now, and it's not a vintage piece of equipment from the 60s.

I would suggest using uint8_t instead, just like you're using uint16_t a few lines below.



Correct me if I'm wrong but...

It is impossible for unsigned char to be 32 bits and for uint8_t to exist, on a conformant C/C++ implementation. The sizeof char / unsigned char is 1 ("byte" is defined this way). So if 1 byte is more than 8 bits, there cannot be an uint8_t type, since that would make sizeof uint8_t less than 1.

Actually, combined with the requirement for char to have at least 8 bits, is follows that uint8_t can only possibly exist if char has 8 bits.

Edit: quoting C99, to show that uint8_t must not have padding bits (an assumption in this reasoning). The requirement for uintN_t to have no padding seems omitted in the second paragraph (I assume by mistake), but the third one suggests it really should have no padding.

The typedef name intN_t designates a signed integer type with width N, no padding bits, and a two’s complement representation. Thus, int8_t denotes a signed integer type with a width of exactly 8 bits.

The typedef name uintN_t designates an unsigned integer type with width N. Thus, uint24_t denotes an unsigned integer type with a width of exactly 24 bits.

These types are optional. However, if an implementation provides integer types with widths of 8, 16, 32, or 64 bits, no padding bits, and (for the signed types) that have a two’s complement representation, it shall define the corresponding typedef names.


I don't know if you can have a conformant implementation, but to be honest, I never really thought about it. Non-conformant (subtly or not-so-subtly) compilers are something that I have come to accept with resignation. I may not like them, but software has to be written, and it's not going to wait for another team of developers to get their compiler right.

At the moment, each one of the two codebases I'm maintaining has about a dozen workarounds for compiler bugs. One of the compilers is already at its 6th major version.

It's things like these that bring a smile to my face whenever I see people valiantly calling for rewriting everything in Rust :-).


At least you'll have some hope of knowing what's going on when you try to compile the code and uint8_t doesn't exist.


In my experience, these platforms with non-8-bit-bytes or non-byte-adressable memory are things like DSPs and other niche processors, and if you want to port/write software for them, there are plenty of other quirks than the size of a char.


A very valid point! I'll update the code.


Glad I could help. Your little project is pretty ambitious; I hope it turns out all right -- best of luck! You certainly started well.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: