Liste des Groupes | Revenir à c arch |
On 09/09/2024 08:56, Terje Mathisen wrote:David Brown wrote:On 05/09/2024 19:04, Terje Mathisen wrote:David Brown wrote:On 05/09/2024 11:12, Terje Mathisen wrote:David Brown wrote:Unsigned types are ideal for "raw" memory access or external data,
for anything involving bit manipulation (use of &, |, ^, << and >>
on signed types is usually wrong, IMHO), as building blocks in
extended arithmetic types, for the few occasions when you want
two's complement wrapping, and for the even fewer occasions when
you actually need that last bit of range.
That last paragraph enumerates pretty much all the uses I have for
integer-type variables, with (like Mitch) a few apis that use (-1)
as an error signal that has to be handled with special code.
You don't have loop counters, array indices, or integer arithmetic?
Loop counters of the for (i= 0; i < LIMIT; i++) type are of course
fine with unsigned i, arrays always use a zero base so in Rust the
only array index type is usize, i.e the largest supported unsigned
type in the system, typically the same as u64.
Loop counters can usually be signed or unsigned, and it usually makes
no difference. Array indices are also usually much the same signed or
unsigned, and it can feel more natural to use size_t here (an unsigned
type). It can make a difference to efficiency, however. On x86-64,
this code is 3 instructions with T as "unsigned long int" or "long
int", 4 with "int", and 5 with "unsigned int".
int foo(int * p, T x) {
int a = p[x++];
int b = p[x++];
return a + b;
}
;; assume *p in rdi, x in rsi
mov rax,[rdi+rsi]
add rax,[rdi+rsi+8]
ret
Yes - that's three instructions for 64-bit type T. (To be clear, I had
counted the "ret" here.)
With 32-bit int for T, you need a "movsx rsi, esi" first to sign-extend
the 32-bit int parameter "x" to 64 bits. (That could be different for
different ABI's.) With 32-bit unsigned int for T you need an additional
instruction to make sure the result of the first "x++" is wrapped as
32-bit unsigned.
:-)
Or you could just write sane code that matches what you want to say.
Of course the fine line between "smart code" and "smart-arse code" is
somewhat subjective!
It also varies over time, and depends on the needs of the code.
Sometimes it makes sense to prioritise efficiency over readability - but
that is rare, and has been getting steadily rarer over the decades as
processors have been getting faster (disproportionally so for
inefficient code) and compilers have been getting better.
Often you get the most efficient results by writing code clearly and
simply so that the compiler can understand it better and good object
code. This is particularly true if you want the same source to be used
on different targets or different variants of a target - few people can
track the instruction scheduling and timings on multiple processors
better than a good compiler. (And the few people who /can/ do that
spend their time chatting in comp.arch instead of writing code...) When
you do hand-made micro-optimisations, these can work against the
compiler and give poorer results overall.
This is especially the case
when code is moved around with inlining, constant propagation,
unrolling, link-time optimisation, etc.
Long ago, it was a different matter - then compilers needed more help to
get good results. And compilers are far from perfect - there are still
times when "smart" code or assembly-like C is needed (such as when
taking advantage of some vector and SIMD facilities).
Les messages affichés proviennent d'usenet.