1

I have a char xyz[2]; I receive 2 octet numbers in network byte order in xyz[0] and xyz[1].How do i change this to host order. How do i use ntohs to convert xyz. Please help.

Ershad
  • 947
  • 2
  • 20
  • 40

3 Answers3

5

Do you mean "How do I convert a data stream in network order to a data stream in host order?" In that case you can use the ntohs()/htons() functions. Be careful how you invoke those, though, since you may have to take alignment issues into account. The universal solution would be to do a manual swapping of the (or each) pair of bytes.

On the other hand, if you want to deserialize data that comes to you in network order, and you want to use the values that are serialized in the data in your program, then the notion of a "host order" is a red herring. All you need to know whether the data that you receive is in big-endian or little-endian order:

unsigned short int le_value = xyz[0] + (xyz[1] << 8);   // little-endian
unsigned short int be_value = xyz[1] + (xyz[0] << 8);   //    big-endian

This is a typical hallmark of platform-independent programming: Your program interna should be entirely independent of implementation details, and fixed implementations have to be specified precisely at the program boundaries (i.e. (de)serialization).

Note that in general, you cannot just take an existing byte buffer and interpret it as a different value in place, since that is not allowed by the standard. That is, you can only treat data as an int that has been declared as an int. For example, the following is illegal: char * buf = get(); int a = *(int*)buf;. The legal version starts with the target type: int a; get_data((char*)&a);

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 1
    Host order is not a read herring as not all hosts have the same endianess. This is a typical **WRONG** way of doing it. It make me cry when I see this as it is non portable. htonl() and family are designed specifically for this task doing it manually is non portable. – Martin York Nov 16 '11 at 16:33
  • 1
    @LokiAstari: That's only relevant in as far as you consider "host order" as another serialization format. Internally to the program it has no meaning, because the *language* doesn't even have a concept of "ordering". In the language there are only values. Binary representations are a property of the implementation and of serialized data. – Kerrek SB Nov 16 '11 at 17:13
  • @KerrekSB: The OP is about deserialization, and your answer deserializes in a platform dependant manner, by assuming specific implementation details. (That the "host order" is opposite the "network order") – Mooing Duck Nov 16 '11 at 17:16
  • @MooingDuck: What now? I'm completely lost how you conclude that. The *only* assumption I make is about the format of the serialized data. You do not need any knowledge of your language's implementation to understand values. When you say `int a = 5;`, you don't need to know if the high or the low bits get set. – Kerrek SB Nov 16 '11 at 17:17
  • 1
    @KerrekSB: If the OP had said I want to convert a 16bit value from network byte order to hardware platform 'A' then host would have been a red herring. But he asked for host order which implies a requirement for portability across different types of host connect to a network. The language may not have the concept of host ordering but the platform does and network orientated programs must take this into consideration. Thus there is already a set of libraries specifically designed to cope and handle this type of transformation. – Martin York Nov 16 '11 at 17:18
  • I see now how the OP's question sounds more like a format conversion question than a deserialization question. I've added that to my answer. – Kerrek SB Nov 16 '11 at 17:21
  • @LokiAstari: Yes, I get that now. Cheers. I added that to my answer. – Kerrek SB Nov 16 '11 at 17:21
  • I still disagree with your statement: `The universal solution would be to do a manual swapping`. This is not the universal solution. I think you will find that this is a personal opinion you have. Network orientated programs (that are designed to be portable) will use the htonl() family. – Martin York Nov 16 '11 at 17:31
  • 1
    @LokiAstari: "universal" in the sense that it's always a correct C program for any pointer you give it. If you have additional information, you can override this with a more efficient implementation (e.g. `htons` if you are aligned for `short`). But when you think generically, you have to start with an algorithm that *always* works, before moving on to the optimizations. – Kerrek SB Nov 16 '11 at 17:41
  • @Kerrek SB: But not universal in the sense that it is brittle and prone to porting errors (thus it any sense of the term correct its broken). Either you need to wrap that code in #defines to validate that you are on a tested platform or you need to use htonl(). – Martin York Nov 17 '11 at 00:43
2

Try this:

uint16_t  result = ntohs(*(uint16_t*)xyz);
Martin York
  • 257,169
  • 86
  • 333
  • 562
dbrank0
  • 9,026
  • 2
  • 37
  • 55
  • @KerrekB it may be UB by the standard. But the implementers of ntohs() have written it specifically for the platform. And designed it to work. UB does not mean wrong. In this case they are using the UB to give you something that works on this platform. – Martin York Nov 16 '11 at 16:29
  • @dbrank0: You should use uint16_t as short unsigned int is not guaranteed to be 16 bits. – Martin York Nov 16 '11 at 16:32
  • @LokiAstari: The left cast is undefined behavior, not the `ntohs`. `ntohs` is perfectly fine on a `short`, but the way in which the short is obtained in this code is not. – Kerrek SB Nov 16 '11 at 17:13
  • @KerrekSB: UB for the standard not the function. – Martin York Nov 16 '11 at 17:24
  • 1
    @LokiAstari: The cast is in the user's code. The cast is Undefined Behavior. What the `ntohs` function does or expects is not relevant to what KerrekSB is describing. – Mooing Duck Nov 16 '11 at 17:36
0

use std::swap if you know that the host order and the network order are different or do nothing?

Alexander Oh
  • 24,223
  • 14
  • 73
  • 76