Es geht um eine Popcount-Routine mit Bit-Twiddling. Die funktioniert
auch, aber nicht mehr, wenn man die Konstanten alle mit dem Suffix UL
als unsigned long markiert, obwohl das gehen sollte. Gemäß integer
promotion müßte das IMO ohnehin nach UL (32 bit) promoted werden.
Drei Versionen: die erste ohne Suffixe, die zweite soweit, daß es noch
geht, die dritte geht nicht mehr. Also wenn man in der Zeile mit der
Multiplikation nicht nur U, sondern UL hinzufügt (egal zu welcher der
Konstanten), scheitert es mit verkehrtem Ergebnis.
Getestet mit GCC 9.3.0 64 Bit unter Linux, keine Warnungen erschienen.
1 | /*
|
2 | compile with: gcc -O0 -std=c99 -Wall -Wextra
|
3 | see Bit Twiddling Hacks:
|
4 | https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
|
5 | */
|
6 |
|
7 | #include <stdint.h>
|
8 | #include <stdio.h>
|
9 |
|
10 | /*works*/
|
11 | uint32_t popcnt_1(uint32_t v) {
|
12 | v = v - ((v >> 1) & 0x55555555);
|
13 | v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
|
14 | return (((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
|
15 | }
|
16 |
|
17 | /*works*/
|
18 | uint32_t popcnt_2(uint32_t v) {
|
19 | v = v - ((v >> 1) & 0x55555555UL);
|
20 | v = (v & 0x33333333UL) + ((v >> 2) & 0x33333333UL);
|
21 | return (((v + (v >> 4)) & 0xF0F0F0FU) * 0x1010101U) >> 24;
|
22 | }
|
23 |
|
24 | /*wrong result*/
|
25 | uint32_t popcnt_3(uint32_t v) {
|
26 | v = v - ((v >> 1) & 0x55555555UL);
|
27 | v = (v & 0x33333333UL) + ((v >> 2) & 0x33333333UL);
|
28 | return (((v + (v >> 4)) & 0xF0F0F0FUL) * 0x1010101UL) >> 24;
|
29 | }
|
30 |
|
31 | int main (void) {
|
32 | printf("1: 0xFF00 ones: %u\n", popcnt_1(0xFF00UL)); /*result: 8*/
|
33 | printf("2: 0xFF00 ones: %u\n", popcnt_2(0xFF00UL)); /*result: 8*/
|
34 | printf("3: 0xFF00 ones: %u\n", popcnt_3(0xFF00UL)); /*result: 2056*/
|
35 | return 0;
|
36 | }
|