When I look in netinet/in.h on my system it's defined with the type uint32_t. Over here (http://www.beej.us/guide/bgnet/output/html/multipage/sockaddr_inman.html) it's defined as an unsigned long. Why wouldn't they do what they did with IPv6 addresses and just using an array of chars? If they're already using the assumption that CHAR_BIT is 8 for IPv6, why carry the extra, unnecessary assumption that the implementation provides a 32-bit integer type?
The only reason I can really think of is to ensure portability to platforms that use larger chars, but since they aren't going to work with IPv6 structs, why not redesign IPv4 structs?
And if we're fixing that, why not change the following functions:
Why wouldn't they do what they did with IPv6 addresses and just using an array of chars?
Because you'd have to rely on the compiler somehow being able to figure out that it can manipulate the whole thing as a unit; it's also easier to do netmasking etc. IPv6 was not designed as well, they should've used two 64-bit pieces.
Name:
Anonymous2012-12-27 5:05
So they fucking made a mistake when they defined the API for IPV4.
Have a peanut, don't stick it too far up your rectum.
Well, if you want to write fast code for an implementation that supports uint32_t, you could simply cast it to a pointer of that type then dereference it. A portable method would be to convert the array of four chars to an unsigned long in the host format (which has a minimum guaranteed range that allows a 32-bit integer to fit nicely into it) then to convert it back before you push it down the wire.
Even with the minor benefits of being able to treat it as a single arithmetic type, it requires any C implementation providing the same library to support uint32_t (or uint64_t if they were to define the IPv6 address as two objects of that type).
>>5
An array of char can be aligned on any address, so you're not guaranteed that a cast-and-dereference will work (fuck architectures that don't support unaligned access, but just for the sake of argument...)
it requires any C implementation providing the same library to support uint32_t uint32_t is defined in C99, and C89 has long which must be at least 32 bits.
Name:
Anonymous2012-12-27 8:18
>>7 uint32_t is defined in C99, and C89 has long which must be at least 32 bits.
The fixed width types in stdint.h are optional.
Name:
Anonymous2012-12-27 11:00
>>7 An array of char can be aligned on any address, so you're not guaranteed that a cast-and-dereference will work
I guess, but if it does you can always use that under the assumption that it will be faster. If you stick with the portable method (where you convert to the host format if you need to perform operations on the type as a whole), the only assumption required for an implementation of htonl/ntohl that works with void *s is CHAR_BIT == 8.
Name:
Anonymous2012-12-27 11:32
>>1 assuming void* is 32 bit or wider
Also you're shit at designing APIs.
Name:
Anonymous2012-12-27 11:50
If the language of choice doesn't sort out platform dependent shit, and you feel you need to sort this shit out, why the fuck do you still use that language?
Name:
Anonymous2012-12-27 11:55
>>10
Where do I assume that? The implementation for both of those functions would probably be something like this:
return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
}
As I mentioned in >>9, the only assumption made about the host environment is CHAR_BIT == 8.
Name:
122012-12-27 11:56
ptr[3] = val;*
Name:
Anonymous2012-12-28 10:38
Congratulations, your pointless pointer bullshit has just turned a function that cannot fail into a potential crash source.
Name:
Anonymous2012-12-28 10:52
>>14
More importantly, it allows you to store 32-bit integers in the big-endian byte order on systems that don't provide a 32-bit type.
If you're too useless to call the function correctly then you should probably go back to using Java or VB.
Name:
Anonymous2012-12-28 11:11
>>12
You're making size assumptions, and you can't dereference void pointers. Your solution will not work. Second, if you look in bits/byteswap.h (included from netinet/in.h) you'll see that on i486 and AMD64 processors it's implemented with single instruction inline assembly.
Name:
Anonymous2012-12-28 11:25
>>16 You're making size assumptions
The only assumption I'm making is that chars are 8 bits. If that assumption is true, then you can portably send a 32-bit integer with the network byte order like so:
unsigned char buf[4];
send(fd, htonl(buf, 123456), sizeof buf, 0);
This method makes absolutely no assumptions about the size of short, int, or long, except for the minimum guaranteed limits specified by the C standard.
and you can't dereference void pointers.
That's why the value is converted to a pointer to unsigned char within the body of the function (which is safe since both types are guaranteed to have the same internal representation). Functions like memcpy are designed in a similar way.
Name:
Anonymous2012-12-28 11:25
>>15
An unsigned long int must be at least 32 bits wide. Furthermore, a conforming hosted C99 compiler implementation must provide the uint_least32_t and uint_fast32_t types.
Name:
Anonymous2012-12-28 11:53
>>18
None of those types are guaranteed to be 32-bit types. They could all be 128-bit types, for instance. If they were, then the method I'm suggesting would work (if chars were 8 bits), and the current definitions of ntohl and htonl would be broken since you'd be unable to reliably send out a 32-bit integer. This is basically my main argument.
Name:
Anonymous2012-12-28 12:17
int32_t should be 32 bit long always, ne
Name:
Anonymous2012-12-28 12:31
>>20
ballpoint pen might be tree trunk hat never, en?
Name:
Anonymous2012-12-28 12:39
>>17
Sorry, just woke up when I wrote that and I overlooked the pointer conversion. Regardless, you're taking something that's a one-register inline assembly instruction and turning it into memory laden garbage. Imagine if you're missing cache the first time through as well; now you've replaced a 1 cycle instruction with several multicycle cache fetches AND the initial 400+ cycles of memory latency. Way to fucking go. Also, considering that htonl/ntohl and htons/ntohs are defined in terms of uint32_t and uint16_t, where the hell is the precision problem?
Name:
Anonymous2012-12-28 13:39
>>22
Those are implementation issues. When you're writing low level code you can sacrifice portability for speed in many situations. That's a not a very good sacrifice to make when you're writing interfaces for these libraries that are included by programs which are meant to be portable.
Also, considering that htonl/ntohl and htons/ntohs are defined in terms of uint32_t and uint16_t, where the hell is the precision problem?
I'm not sure what you mean by that. The point is that uint32_t and uint16_t needn't be supported by the C implementation. In >>19 I was assuming those functions would be implemented with unsigned long and unsigned short. Obviously they couldn't be implemented without a 32-bit or 16-bit integer type.
Name:
Anonymous2012-12-28 13:42
>>23 Obviously they couldn't be implemented without a 32-bit or 16-bit integer type.
Why not?
Name:
Anonymous2012-12-28 13:48
>>23
The hton? and ntoh? "functions" are in reality implemented as C preprocessor macros in most implementations. If you're dissatisfied with the old arpa/ junk, why not just use the BSD stuff? #define _BSD_SOURCE /* See feature_test_macros(7) */
#include <endian.h>
uint64_t htonl(uint64_t);
If you change the types to uint64_t, you'd be sending out 8 bytes, like so:
uint64_t n = htonl(123456);
send(fd, &n, sizeof n, 0);
If you change the call to send to this:
send(fd, &n, 4, 0);
Then how do you know the data was moved to the beginning of the object?
Name:
Anonymous2012-12-28 13:57
>>25
Those have the same problem though. The only difference is that it adds functions for handling data in the little endian byte order, as well as 64-bit integers. I'll challenge you to write functions that pack and unpack a 24-bit integer in the same manner as those functions do.
Name:
272012-12-28 13:58
(without padding)
Name:
Anonymous2012-12-28 14:22
>>27,28
But... you can't necessarily write generic endianness correction functions, even when you do know the size of the integer type. For big/little endian it's easy (when you know the size), but using a byte array to return the corrected integer will still put it at an offset if you're trying to use smaller types than the one provided. e.g. you convert an LE 24-bit integer to BE and the unsigned long is 32 bits wide, your data will start at byte_array[1] with byte_array[0]=0. Example: uint24_t u = 0xAABBCC;
uint8_t netbuf[512];
htonl(netbuf, u);
/*
Memory seen as LTR
Memory layout of u: CCBBAA
Memory layout of u when converted to ulong: CCBBAA00
Data in netbuf: 00AABBCC
*/
And now you have zero padding that you need to remove. If you think you can overcome this, please explain how you can get any endianness to conform, no matter how silly (see middle endian for retarded stuff that sadly needs support).
Personally I use tightly packed (not standard, I know) structs and unions when preparing data for sending. My problem is entirely different but solvable. There are no signed conversion functions, but those can be made.
Name:
Anonymous2012-12-28 14:34
And now you have zero padding that you need to remove. If you think you can overcome this, please explain how you can get any endianness to conform, no matter how silly (see middle endian for retarded stuff that sadly needs support).
Uhh, it's actually quite trivial with the method I suggested. If you want to change it to a middle endian format, just switch the array indices around in the hton* and ntoh* functions.
>>29 you convert an LE 24-bit integer to BE and the unsigned long is 32 bits wide
I think you're under the impression that the C environment takes the endianness of the host environment into account. It doesn't since '1 << 1' will yield the value '2' in every single conforming implementation. Think of it like this:
ptr[0] = val / 65536;
ptr[1] = val / 256;
ptr[0] = val;
ptr[0] * 65536 + ptr[1] * 256 + ptr[0]
This is exactly the same as what I wrote in the previous post. a << x is equivalent to a dividied by (two raised to the power of x).
>>31
Oh, and change the last indices in both examples to 2. I don't know why I keep messing that up.
Name:
Anonymous2012-12-28 15:17
>>30-33
Stop making it sound like you can magically conjure up arbitrary endianness switching functions if all you really mean is that there aren't integer types for every possible integer size.
I'm perfectly well aware of how C handles integers when stored as integer variables. We're talking about memory layouts, not registers. Your integers do however have an associated memory layout. If you alias your types a little, i.e. (uint8_t *)&my32bitint, you'll see the byte order.
It's not hard to make a 24-bit integer conversion though. Do the exact same thing as >>30 but return it in a 32-bit integer aligned to the byte index 0. Then again, if you really want these functions I suggest you write them in whatever way you find most convenient, but use the provided endianness functions from endian.h to do the conversion, because, and I can't stress this enough, THEY ARE SINGLE CYCLE INSTRUCTIONS. Also, use uint8_t instead of unsigned char, or typedef your own.
Name:
Anonymous2012-12-28 15:50
>>34 Stop making it sound like you can magically conjure up arbitrary endianness switching functions if all you really mean is that there aren't integer types for every possible integer size.
That function, hton24, converts an unsigned long value to a 24-bit big-endian representation, suitable for sending across a network or storing into a file. It does nothing more than that. If you want to treat it as a single unit, then you can convert it back with ntoh24. If you consider that magic, then I suppose it's magical. Otherwise, it was never my intention to claim that it does things it doesn't.
Do the exact same thing as >>30 but return it in a 32-bit integer aligned to the byte index 0.
I'm quite certain that any values stored in padding bits may be freely discarded in assignments by the C implementation.
and I can't stress this enough, THEY ARE SINGLE CYCLE INSTRUCTIONS
I'll keep that in mind if those functions happen to produce a significant bottleneck in any of my programs.
Also, use uint8_t instead of unsigned char, or typedef your own.
uint8_t was introduced in C99. If unsigned char isn't 8 bits, uint8_t isn't available. If uint8_t is available, unsigned char is 8 bits. It's impractical to use it; you have to include stdint.h every time you want to, and there's a chance your compiler won't support it if they don't support the later standards. I write code so that unsigned char implies an 8-bit quantity. That really is just a matter of preference.
Name:
Anonymous2012-12-28 15:56
wow op i fap so hard my dick bigger 2 inches great vid
>>35
So for you who is clearly incapable of reading and comprehending, here's how endianness works: It's only well defined for byte streams that have a power of two length. First you complain that the network order functions don't store their shit into a byte array because "what if the implementation doesn't have a 32-bit integer type".
Barring that 32-bit integer types are available, or you're on a system that doesn't have any reason to communicate over your average network protocol, it then turns into: "oh but you can't do it for arbitrary sizes with the arpa functions", which is an asinine statement as you might not even be able to write generic functions to switch endianness, as endianness can be whatever the ISA designer wanted it to be. However this just seemed to be a misunderstanding. What you actually meant was "there are no 24-bit integer types (for example), so a byte array would be better".
Given that endianness is still only well defined for 2^n length sequences of bytes, and unless you have a system where you have defined your own conventions you won't see these, why the living fuck should the absolutely ancient functions hton? and ntoh? support your system?
If you have definitions for non-pow2 endianness I'd like to have them though. I'm especially curious of how middle endian looks.
And it's not about those functions being a bottleneck. It's about using that ridiculous CISC processor of yours the way it was intended to be used.