Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p><code>1u &lt;&lt; 8u</code> is <code>0x100u</code>, which is larger than every <code>uint8_t</code> value, so the conditional is never satisfied. Your "conversion" routine is actually just:</p> <pre><code>return x; </code></pre> <p>which actually makes some sense.</p> <p>You need to define more clearly what you want for conversion. C99 defines conversion from unsigned to signed integer types as follows (<strong>§6.3.1.3 "Signed and unsigned integers"</strong>)</p> <blockquote> <p>When a value with integer type is converted to another integer type other than <code>_Bool</code>, if the value can be represented by the new type, it is unchanged.</p> <p>…</p> <p>Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.</p> </blockquote> <p>Thus, <code>uint8_t</code> values between <code>0</code> and <code>127</code> are preserved, and the behavior for values larger than <code>127</code> is undefined. <em>Many</em> (but not all) implementations will simply interpret the unsigned values as a twos-complement representation of a signed integer. Perhaps what you're really asking is how to guarantee this behavior across platforms?</p> <p>If so, you can use:</p> <pre><code>return x &lt; 128 ? x : x - 256; </code></pre> <p>The value <code>x - 256</code> is an <code>int</code>, guaranteed to have the value of <code>x</code> interpreted as a twos-complement 8 bit integer. The implicit conversion to <code>int8_t</code> then preserves this value.</p> <p>This all assumes that <code>sint8_t</code> is meant to be <code>int8_t</code>, as <code>sint8_t</code> isn't a standard type. If it isn't, then all bets are off, because the correctness of the conversion I suggested depends on the guarantee that <code>int8_t</code> have a twos-complement representation (<strong>§7.18.1.1 "Exact-width integer types"</strong>).</p> <p>If <code>sint8_t</code> is instead some wacky platform-specific type, it might use some other representation like ones-complement, which has a different set of representable values, thus rendering the conversion described above implementation-defined (hence non-portable) for certain inputs.</p> <hr> <p><strong>EDIT</strong></p> <p>Alf has argued that this is "silly", and that this will never be necessary on any production system. I disagree, but it is admittedly a corner case of a corner case. His argument is not entirely without merit.</p> <p>His claim that this is "inefficient" and should therefore be avoided, however, is baseless. A reasonable optimizing compiler will optimize this away on platforms where it is unnecessary. Using GCC on x86_64 for example:</p> <pre><code>#include &lt;stdint.h&gt; int8_t alf(uint8_t x) { return x; } int8_t steve(uint8_t x) { return x &lt; 128 ? x : x - 256; } int8_t david(uint8_t x) { return (x ^ 0x80) - 0x80; } </code></pre> <p>compiled with -Os -fomit-frame-pointer yields the following:</p> <pre><code>_alf: 0000000000000000 movsbl %dil,%eax 0000000000000004 ret _steve: 0000000000000005 movsbl %dil,%eax 0000000000000009 ret _david: 000000000000000a movsbl %dil,%eax 000000000000000e ret </code></pre> <p>Note that all three implementations are <em>identical</em> after optimization. Clang/LLVM gives exactly the same result. Similarly, if we build for ARM instead of x86:</p> <pre><code>_alf: 00000000 b240 sxtb r0, r0 00000002 4770 bx lr _steve: 00000004 b240 sxtb r0, r0 00000006 4770 bx lr _david: 00000008 b240 sxtb r0, r0 0000000a 4770 bx lr </code></pre> <p>Protecting your implementation against corner cases when it has no cost for the "usual" case is never "silly".</p> <p>To the argument that this adds needless complexity, I say: which is harder -- writing a comment to explain the conversion and why it is there, or your successor's intern trying to debug the problem 10 years from now when a new compiler breaks the lucky happenstance that you've been silently depending on all this time? Is the following really so hard to maintain?</p> <pre><code>// The C99 standard does not guarantee the behavior of conversion // from uint8_t to int8_t when the value to be converted is larger // than 127. This function implements a conversion that is // guaranteed to wrap as though the unsigned value were simply // reinterpreted as a twos-complement value. With most compilers // on most systems, it will be optimized away entirely. int8_t safeConvert(uint8_t x) { return x &lt; 128 ? x : x - 256; } </code></pre> <p>When all is said and done, I agree that this is vaguely over the top, but I also think we should try to answer the question at face value. A better solution, of course, would be for the C standard to pin down the behavior of conversions from unsigned to signed when the signed type is a twos-complement integer without padding (thus specifying the behavior for all of the <code>intN_t</code> types).</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload