0

I am trying to convert a signed integer to byte array.

I tried below code. In this eg, expected result is FD 53 for the input -685(2s complement form).

int exponent = -685;

std::int64_t const exponent_range{std::labs(exponent * (int64_t)2)};
std::uint8_t const exponent_bytes{static_cast<std::uint8_t>((std::log2(static_cast<double>(exponent_range)) / 8.0) + 1.0)};

std::vector<std::uint8_t> bytes;
for (std::uint8_t i = exponent_bytes; i > 0; --i) {
    bytes.push_back(static_cast<std::uint8_t>((exponent >> ((i - 1U) * 8)) & 0xFFU));
}

In the last line I am shifting a signed integer to the right. Is this standard compliant operation or undefined behavior?

Kindly suggest any alternate standard compliant(C99 or C++11) implementation. I need a solution that would work in both byte orderings.

19
  • 1
    Since C++20 signed integer are two's-complement. The ambiguity of signed shifts is therefore gone. All CPUs that have a modern C++ compiler use the same behavior for signed integer shifts, one that preserves the sign bit. I haven't dug deep into it but if the standard doesn't mandate this yet then it's probably just lagging behind the change to mandate two's-complement. Commented Jul 7, 2022 at 16:27
  • I second that. Some rather verbose (and perhaps outdated) answers here. Commented Jul 7, 2022 at 16:28
  • With C++20 the section for bitwise shift got shorter by a considerable amount: en.cppreference.com/w/cpp/language/operator_arithmetic Commented Jul 7, 2022 at 16:36
  • 1
    As for the soundness of the algorithm overall: That code seems horribly convoluted and broken. An exponent of 0 will use 0 bytes, an exponent < 128 will use 1 byte, an exponent < 32768 will use 2 bytes, an exponent < 16mil will use 3 bytes, an exponent up to 1bil will use 4 bytes and then it will cause UB, Commented Jul 7, 2022 at 16:36
  • 1
    Does this answer your question? C++ int to byte array Commented Jul 8, 2022 at 2:46

1 Answer 1

0

I used memcpy to convert signed to unsigned integer. It looks like it will respect the byte ordering.

  int exponent = -685;

  std::int64_t const exponent_range{std::llabs(exponent * 2ll)};
  std::uint8_t const exponent_bytes{static_cast<std::uint8_t>((std::log2(static_cast<double>(exponent_range)) / 8.0) + 1.0)};

  uint32_t exponent_raw;
  std::memcpy(&exponent_raw, &exponent, sizeof(exponent));
  std::vector<std::uint8_t> bytes;
  for (std::uint8_t i = exponent_bytes; i > 0; --i) {
    bytes.push_back(static_cast<std::uint8_t>((exponent_raw >> ((i - 1U) * 8)) & 0xFFU));   
  }  
Sign up to request clarification or add additional context in comments.

1 Comment

If you're going for portability, I figure I should mention that fixed-width integer types are not always defined. If a system has more than 8 bits in a "byte" (addressable unit), like some modern DSPs, then it's likely that these fixed-width integer types will not be available. And since your question is about converting an int to an array of "bytes" (addressable units, like a char), assumptions about the size of a byte are unnecessary. I think treating this as a byte-level addressing problem, coupled with an endianness-checking problem, will give a cleaner solution; see my other comments.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.