Ik wil voor een programma een boolean array gebruiken, maar ik wil met 1 bepaalde standaard waarde beginnen voor de gehele array inhoud. Nu is dat wel op te lossen met een for loopje en alle waarden op false/true zetten, maar kan dat niet korter?
Kijk eens naar memset:
http://www.cplusplus.com/...brary/cstring/memset.html
edit: je kan ook opzoek in de c++ docs naar std::fill()
http://www.cplusplus.com/...brary/cstring/memset.html
edit: je kan ook opzoek in de c++ docs naar std::fill()
[ Voor 24% gewijzigd door beany op 05-12-2008 15:16 ]
Dagelijkse stats bronnen: https://x.com/GeneralStaffUA en https://www.facebook.com/GeneralStaff.ua
C++:
1
2
| bool *arr = new bool[100]; for(int i = 0; i < 100; i++) arr[i] = true; |
werkt prima en is goed leesbaar. Voor performance zou je regel 2 kunnen vervangen met:
C++:
1
| memset(arr, 0xFF, 100 * sizeof(bool)); |
-niks-
Ik zou std::fill gebruiken. Ik geloof dat "any nonzero value" gelijk moet staan aan true, maar in de praktijk geeft dit soms toch wat problemen, en een std::fill zet alle bools gewoon letterlijk op 'true' (1 dus, zoals het for-lusje zou doen), en niet op 0xff.
Overigens zou ik normaal sowieso een std::vector aanraden ipv een standaard array (kun je ook meteen de default waarde bij initialisatie instellen), maar helaas is een std::vector<bool> niet wat je denkt dat het is. Je zou evt. kunnen overwegen om gewoon een std::vector<char> te gebruiken.
Overigens zou ik normaal sowieso een std::vector aanraden ipv een standaard array (kun je ook meteen de default waarde bij initialisatie instellen), maar helaas is een std::vector<bool> niet wat je denkt dat het is. Je zou evt. kunnen overwegen om gewoon een std::vector<char> te gebruiken.
C++:
1
| std::vector<char> arr(100, true); |
[ Voor 40% gewijzigd door .oisyn op 05-12-2008 15:58 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Een array in C++? Het kan wel maar als je toch bezig bent waarom dan niet gewoon
C++:
1
2
3
| unsigned grootte = 100; std::vector<bool> vec(grootte); std::fill(vec.begin(), vec.end(), true); |
Omdat std::vector<bool> niet is wat je denkt dat het is en imho beter vermeden kan worden. Daarnaast zou ik in dat geval nog altijd gebruik maken van de initialisatie-mogelijkheid van vector, zoals ik in mijn vorige voorbeeld liet zien. Dan is die hele fill overbodig.
[ Voor 49% gewijzigd door .oisyn op 05-12-2008 16:00 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
oja dat was een speciale implementatie die 8 bools in een byte propt toch? nouja dan maak je er char van en dan is dat 'probleem' opgelost.oisyn schreef op vrijdag 05 december 2008 @ 15:59:
Omdat std::vector<bool> niet is wat je denkt dat het is en imho beter vermeden kan worden. Daarnaast zou ik in dat geval nog altijd gebruik maken van de initialisatie-mogelijkheid van vector, zoals ik in mijn vorige voorbeeld liet zien. Dan is die hele fill overbodig.
std::deque<bool> heeft die problemen niet en kan in dit geval prima gebruikt worden.oisyn schreef op vrijdag 05 december 2008 @ 15:56: maar helaas is een std::vector<bool> niet wat je denkt dat het is
[ Voor 25% gewijzigd door PrisonerOfPain op 05-12-2008 16:18 ]
Maar dat is tevens ook geen equivalent alternatief voor een array.
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
een array is een array
een std::vector<T> is een namaak-array, die mogelijk resizable is
een std::vector<bool> is een apart geval
de topictitel beschrijft duidelijk een array
C definieert false gelijk aan nul, en true als niet gelijk aan nul, dus mijn memset van een paar posts hoger had net zo goed 0x01 ipv 0xFF kunnen zijn (of zelfs, true denk ik).
Maar om concreet antwoord te geven aan de TS, in C(++) is geheugen wat je alloceert danwel op je stack per definitie niet geinitialiseert, dus moet dat in code gedaan worden. Of je het dan zelf doet (met een for-loop of een memset) of voor je laat doen (met een STL container) maakt niet uit, gedaan moet het toch.
Het kan dus niet "korter" (het kost je hoe dan ook CPU cycles), tenzij je "korter" in code bedoelt, en in dat geval is een single-line for loop of een single-line memset (zoals hierboven door mij gegeven) toch vrij kort imho.
een std::vector<T> is een namaak-array, die mogelijk resizable is
een std::vector<bool> is een apart geval
de topictitel beschrijft duidelijk een array
C definieert false gelijk aan nul, en true als niet gelijk aan nul, dus mijn memset van een paar posts hoger had net zo goed 0x01 ipv 0xFF kunnen zijn (of zelfs, true denk ik).
Maar om concreet antwoord te geven aan de TS, in C(++) is geheugen wat je alloceert danwel op je stack per definitie niet geinitialiseert, dus moet dat in code gedaan worden. Of je het dan zelf doet (met een for-loop of een memset) of voor je laat doen (met een STL container) maakt niet uit, gedaan moet het toch.
Het kan dus niet "korter" (het kost je hoe dan ook CPU cycles), tenzij je "korter" in code bedoelt, en in dat geval is een single-line for loop of een single-line memset (zoals hierboven door mij gegeven) toch vrij kort imho.
[ Voor 2% gewijzigd door MLM op 05-12-2008 16:55 . Reden: kromme zin ]
-niks-
En de suggestie beschrijft duidelijk een vector. Mogen we niets meer suggereren?MLM schreef op vrijdag 05 december 2008 @ 16:54:
een array is een array
een std::vector<T> is een namaak-array, die mogelijk resizable is
een std::vector<bool> is een apart geval
de topictitel beschrijft duidelijk een array
Zoals ik al zei, de standaard doet dat idd, maar in de praktijk kun je problemen tegenkomen als bools niet exact gelijk zijn aan true. Ik ben ze tegengekomen, maar ik weet de exacte toedracht niet helemaal meer... kon zijn dat als je mijnBool == true deed, daar false uitkwam als de byte waarin mijnBool werd opgeslagen een waarde had die niet exact 'true' (1 dus) was, maar wel een andere waarde dan 0C definieert false gelijk aan nul, en true als niet gelijk aan nul, dus mijn memset van een paar posts hoger had net zo goed 0x01 ipv 0xFF kunnen zijn (of zelfs, true denk ik).
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
De standaard zegt in ieder geval dat als een integer geïnterpreteert wordt als boolean, nul correspondeert met false en andere waarden met true, maar geldt dat ook voor een bitpatroon dat je in een boolean object kunt schrijven? Dat kan ik me eigenlijk niet voorstellen, want dat betekent dat de compiler er eigenlijk nooit vanuit kan gaan dat een boolean waarde in het geheugen genormaliseerd is naar 1/0 (of twee andere waarden) en dan worden alle vergelijkingen dus een stuk ingewikkelder (en minder efficient).
Je zou memset(1, array, sizeof(array)) kunnen gebruiken, maar eigenlijk moet je dan zeker weten dat true gerepresenteert wordt door 1 én dat booleans precies 1 byte groot zijn; dat laatste is zeker niet altijd het geval. (Ik gebruik zelf memset eigenlijk alleen om geheugen op nul te zetten, of om character arrays te vullen.)
Als je voor portability gaat, is een vector<char>(lengte,1) dus waarschijnlijk een beter idee, of gewoon je array toch handmatig vullen d.m.v. een for-lusje of std::fill, wat eigenlijk nauwelijks meer code is dan memset gebruiken.
Je zou memset(1, array, sizeof(array)) kunnen gebruiken, maar eigenlijk moet je dan zeker weten dat true gerepresenteert wordt door 1 én dat booleans precies 1 byte groot zijn; dat laatste is zeker niet altijd het geval. (Ik gebruik zelf memset eigenlijk alleen om geheugen op nul te zetten, of om character arrays te vullen.)
Als je voor portability gaat, is een vector<char>(lengte,1) dus waarschijnlijk een beter idee, of gewoon je array toch handmatig vullen d.m.v. een for-lusje of std::fill, wat eigenlijk nauwelijks meer code is dan memset gebruiken.
boost::dynamic_bitset 
Of een bool maken die default naar true construct.
Dan kan je ook meteen een std::vector gebruiken.
Of een bool maken die default naar true construct.
C++:
1
2
3
4
5
6
7
8
9
10
11
12
| struct my_bool { my_bool() : value(true) {} my_bool(bool b) : value(b) {} operator bool () {return value;} ~my_bool() {} bool value; }; std::vector<my_bool> ar; |
Dan kan je ook meteen een std::vector gebruiken.
[ Voor 86% gewijzigd door Zoijar op 05-12-2008 21:30 ]
Daar dacht ik ook meteen aan. De compiler gebruikt voor zover ik weet de laatste waarde om de rest op te vullen. Ik weet echter niet zeker of dit in C, C++ of beide het geval is.
ASSUME makes an ASS out of U and ME
Het eerste element word false (expliciet opgegeven), de rest word ook false (standaard waarde)Ghannes schreef op zaterdag 06 december 2008 @ 09:01:
Vul je dan niet enkel b\[0]?
Volgens mij zet hij ze gewoon op 0 (wat toevallig false is), dus dat werkt niet.
Lijkt me wel eigenlijk, In dit geval:Soultaker schreef op vrijdag 05 december 2008 @ 18:13:
De standaard zegt in ieder geval dat als een integer geïnterpreteert wordt als boolean, nul correspondeert met false en andere waarden met true, maar geldt dat ook voor een bitpatroon dat je in een boolean object kunt schrijven?
code:
1
2
3
4
5
6
7
8
9
| union T1 { struct T2 { int32_t bitf1 : 16; int32_t bitf2 : 16; }bitval; int32_t intval; }; |
Zou een bool( T1.intval ) altijd true moeten opleveren bij elke bitval.bitf1 of bitval.bitf2 die != 0.
[edit]
Owh wacht, dat was niet wat je bedoelde ..
[ Voor 14% gewijzigd door farlane op 06-12-2008 14:21 ]
Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.
Ik moet toegeven dat ik deze situatie nooit ben tegengekomen in de praktijk. Hoe dan ook heb je te maken met een compiler die zich niet aan de standaard houd. Mogelijk oplossing dan:.oisyn schreef op vrijdag 05 december 2008 @ 17:34:
[...]
Zoals ik al zei, de standaard doet dat idd, maar in de praktijk kun je problemen tegenkomen als bools niet exact gelijk zijn aan true. Ik ben ze tegengekomen, maar ik weet de exacte toedracht niet helemaal meer... kon zijn dat als je mijnBool == true deed, daar false uitkwam als de byte waarin mijnBool werd opgeslagen een waarde had die niet exact 'true' (1 dus) was, maar wel een andere waarde dan 0
C:
1
| memset(array, true, sizeof(bool) * items); |
Tevreden?
Volgens mij gaat de compiler daar dan dus ook niet van uitquote: SoultakerDe standaard zegt in ieder geval dat als een integer geïnterpreteert wordt als boolean, nul correspondeert met false en andere waarden met true, maar geldt dat ook voor een bitpatroon dat je in een boolean object kunt schrijven? Dat kan ik me eigenlijk niet voorstellen, want dat betekent dat de compiler er eigenlijk nooit vanuit kan gaan dat een boolean waarde in het geheugen genormaliseerd is naar 1/0 (of twee andere waarden) en dan worden alle vergelijkingen dus een stuk ingewikkelder (en minder efficient).
-niks-
Kan je dat eens uitleggen in mensentaal?.oisyn schreef op vrijdag 05 december 2008 @ 15:59:
Omdat std::vector<bool> niet is wat je denkt dat het is en imho beter vermeden kan worden. Daarnaast zou ik in dat geval nog altijd gebruik maken van de initialisatie-mogelijkheid van vector, zoals ik in mijn vorige voorbeeld liet zien. Dan is die hele fill overbodig.
En een wrapper maken rond die booleans? Gaat dat? Een struct bijvoorbeeld?
[ Voor 18% gewijzigd door Snake op 06-12-2008 13:55 ]
Going for adventure, lots of sun and a convertible! | GMT-8
Dan heb je een struct waar je alsnog een memset/forloop/std::fill functie in moet maken. Dan verschuif je het "probleem" naar een andere plaats, waar je het dan alsnog moet oplossenSnake schreef op zaterdag 06 december 2008 @ 13:52:
[...]
Kan je dat eens uitleggen in mensentaal?(van die std::vector<bool>, waarom dat dat niet mag. Heb het al.
En een wrapper maken rond die booleans? Gaat dat? Een struct bijvoorbeeld?
-niks-
Nou ja, GCC lijkt in ieder geval wél van genormaliseerde waarden uit te gaan, en de gegenereerde code wordt daar toch echt wel simpeler van. Natuurlijk, als je één operand hebt dan kun je meestal gratis de zero flag bekijken om te bepalen of 'ie nul is, maar als je twee waarden wil vergelijken moet je meer werk doen:MLM schreef op zaterdag 06 december 2008 @ 13:47:
Volgens mij gaat de compiler daar dan dus ook niet van uitTevens is dit niet ingewikkelder, het is eerder een hardware optimalisatie die in C terecht gekomen is, je kan de zero flag van de processor gebruiken om te checken of een register true danwel false is
C++:
1
2
| int foo(bool a, bool b) { return (a != 0) == (b != 0); } int bar(char a, char b) { return (a != 0) == (b != 0); } |
Levert deze assembly op:
GAS:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| foo: pushl %ebp movl %esp, %ebp movzbl 12(%ebp), %eax cmpb %al, 8(%ebp) sete %al movzbl %al, %eax popl %ebp ret bar: pushl %ebp movl %esp, %ebp cmpb $0, 8(%ebp) sete %al cmpb $0, 12(%ebp) popl %ebp setne %dl xorl %edx, %eax movzbl %al, %eax ret |
Zoals je ziet is de code voor de tweede functie wel degelijk ingewikkelder.
Een ander voorbeeld:
C++:
1
2
3
4
5
6
7
| #include <assert.h> int main() { bool foo[4]; *(int*)foo = 0x01020304; assert(foo[1] == foo[2]); } |
Hoewel alle vier waarden non-zero zijn, zijn ze niet gelijk. memset() gebruiken is dus alleen een goed idee als je zeker weet dat het bitpatroon wat je gebruikt overeenkomt met wat de compiler gebruikt, en dus per definitie niet portable.
Dat werkt nog steeds niet met multi-byte bools; de compiler verwacht dan b.v. een 4-bytes lange waarde 1, maar je hebt 0x01010101 geschreven. Het probleem blijft dat memset() alleen bytes schrijft, en dat maakt die functie niet zo geschikt voor het vullen van elementen die groter zijn dan een byte (hoewel 0 en -1 nog wel werken).Mogelijk oplossing dan:
C:
1 memset(array, true, sizeof(bool) * items);
Overigens kun je die true in de argumentlijst net zo goed vervangen door 1, want het argument van memset() is een int, en een conversie van true naar int levert per definitie 1 op, ook als de interne representatie anders is.
[ Voor 19% gewijzigd door Soultaker op 06-12-2008 15:46 ]
Snake schreef op zaterdag 06 december 2008 @ 13:52:
En een wrapper maken rond die booleans? Gaat dat? Een struct bijvoorbeeld?
Soms heb ik echt het idee dat ik onzichtbaar ben hierMLM schreef op zaterdag 06 december 2008 @ 14:05:
Dan heb je een struct waar je alsnog een memset/forloop/std::fill functie in moet maken. Dan verschuif je het "probleem" naar een andere plaats, waar je het dan alsnog moet oplossen
Verbeterde versie:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| template <typename T, T X = T()> struct default_type { default_type() : value(X) {} default_type(T b) : value(b) {} template <T Y> default_type(const default_type<T, Y>& src) : value(src.value) {} template <bool Y> default_type<T, X>& operator=(const default_type<T, Y>& src) { value = src.value; return *this; } operator T() {return value;} ~default_type() {} T value; }; typedef default_type<bool, true> default_true_bool; typedef default_type<bool, false> default_false_bool; int main() { default_true_bool ar1[10]; default_false_bool ar2[10]; for (int i=0; i<10; ++i) std::cout << std::boolalpha << ar1[i] << " "; std::cout << std::endl; for (int i=0; i<10; ++i) std::cout << std::boolalpha << ar2[i] << " "; std::cout << std::endl; return 0; } |
(haha, ok, genoeg... ach ja, nu heb je ook meteen default_type<int, 42>
[ Voor 59% gewijzigd door Zoijar op 06-12-2008 17:20 ]
Ik zie in jouw ASM helemaal nergens dat er getest word met een expliciete waarde (dat is toch het punt wat je wilt maken, dat bool geoptimized word op een specifieke waarde)Soultaker schreef op zaterdag 06 december 2008 @ 15:39:toon volledige bericht
[...]
Nou ja, GCC lijkt in ieder geval wél van genormaliseerde waarden uit te gaan, en de gegenereerde code wordt daar toch echt wel simpeler van. Natuurlijk, als je één operand hebt dan kun je meestal gratis de zero flag bekijken om te bepalen of 'ie nul is, maar als je twee waarden wil vergelijken moet je meer werk doen:
C++:
1 2 int foo(bool a, bool b) { return (a != 0) == (b != 0); } int bar(char a, char b) { return (a != 0) == (b != 0); }
Levert deze assembly op:
GAS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 foo: pushl %ebp movl %esp, %ebp movzbl 12(%ebp), %eax cmpb %al, 8(%ebp) sete %al movzbl %al, %eax popl %ebp ret bar: pushl %ebp movl %esp, %ebp cmpb $0, 8(%ebp) sete %al cmpb $0, 12(%ebp) popl %ebp setne %dl xorl %edx, %eax movzbl %al, %eax ret
Zoals je ziet is de code voor de tweede functie wel degelijk ingewikkelder.
Anyway, voor compleetheid:
C++:
1
2
| int foo(bool a, bool b) { return (a != 0) == (b != 0); } int bar(char a, char b) { return (a != 0) == (b != 0); } |
Wat compiled tot (MS VS 2008, optimize)
GAS:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| foo: xor eax, eax cmp BYTE PTR _a$[esp-4], al setne al xor ecx, ecx cmp BYTE PTR _b$[esp-4], cl setne cl xor edx, edx cmp eax, ecx sete dl mov eax, edx ret 0 bar: xor eax, eax cmp BYTE PTR _a$[esp-4], al setne al xor ecx, ecx cmp BYTE PTR _b$[esp-4], cl setne cl xor edx, edx cmp eax, ecx sete dl mov eax, edx ret 0 |
ie: hetzelfde
Je hebt gelijk. Maar zie dit:Een ander voorbeeld:
C++:
1 2 3 4 5 6 7 #include <assert.h> int main() { bool foo[4]; *(int*)foo = 0x01020304; assert(foo[1] == foo[2]); }
Hoewel alle vier waarden non-zero zijn, zijn ze niet gelijk. memset() gebruiken is dus alleen een goed idee als je zeker weet dat het bitpatroon wat je gebruikt overeenkomt met wat de compiler gebruikt, en dus per definitie niet portable.
C++:
1
2
3
4
5
6
7
8
9
10
| #include <stdio.h> #include <assert.h> int main() { bool foo[4]; *(int*)foo = 0x01020304; for(int i = 0; i < 4; i++) printf("%d: %s\n", i, foo[i] ? "true" : "false"); assert(foo[1] && foo[2]); } |
Dit werkt zonder probleem bij mij, met alles "true"
Ik ben wel beniewd wat de standaard hier dan van maakt, dat ga ik zo even op zoeken
Toch zouden per definitie alle waarden niet gelijk aan nul als true moeten evalueren.Dat werkt nog steeds niet met multi-byte bools; de compiler verwacht dan b.v. een 4-bytes lange waarde 1, maar je hebt 0x01010101 geschreven. Het probleem blijft dat memset() alleen bytes schrijft, en dat maakt die functie niet zo geschikt voor het vullen van elementen die groter zijn dan een byte (hoewel 0 en -1 nog wel werken).
Overigens kun je die true in de argumentlijst net zo goed vervangen door 1, want het argument van memset() is een int, en een conversie van true naar int levert per definitie 1 op, ook als de interne representatie anders is.
Ik heb een theorie dat op het moment dat de compiler als optimalisatie true en false wel degelijk vaste waarden geeft en als een bool niet 1 van die 2 waarden bevat, je undefinied behaviour krijgt, ONDANKS dat de standaard dat wel degelijk definieert
Meer tests met meer compilers gewenst...
-niks-
Haha, GCC is vet slimMLM schreef op zaterdag 06 december 2008 @ 18:20:
Ik zie in jouw ASM helemaal nergens dat er getest word met een expliciete waarde (dat is toch het punt wat je wilt maken, dat bool geoptimized word op een specifieke waarde)
[ Voor 9% gewijzigd door Zoijar op 06-12-2008 20:43 ]
Je had wel gezien dat de assembly code verschillend is (simpeler voor de bools)? De compiler gaat er vanuit dat bools in het geheugen nul óf 1 zijn en de vergelijking met 0 dus overbodig is voor bools. Dat is toch wel een verschil, en het demonstreert mijn punt dat de compiler aanneemt dat bools in het geheugen maar een beperkt aantal geldige waarden mogen hebben (en dus niet alle waarden die een byte kan aannemen).MLM schreef op zaterdag 06 december 2008 @ 18:20:
Ik zie in jouw ASM helemaal nergens dat er getest word met een expliciete waarde (dat is toch het punt wat je wilt maken, dat bool geoptimized word op een specifieke waarde)
Met GCC werkt deze code sowieso niet goed vanwege aliasing problemen (mijn code had daar trouwens ook last van) maar los daarvan blijkt het van hetoptimalisatieniveau af te hangen of de assertion faalt (zonder optimalisaties triggert 'ie toevallig wél).Maar zie dit:
C++:
1 2 3 4 5 6 7 8 9 10 #include <stdio.h> #include <assert.h> int main() { bool foo[4]; *(int*)foo = 0x01020304; for(int i = 0; i < 4; i++) printf("%d: %s\n", i, foo[i] ? "true" : "false"); assert(foo[1] && foo[2]); }
Dit werkt zonder probleem bij mij, met alles "true"
Dat het for-lusje wel werkt zegt eigenlijk niets over wat de compiler wel of niet aanneemt; natuurlijk zal de compiler de zero-flag gebruiken als die als side-effect al gezet is. Ook wil ik wel geloven dat Microsoft's compiler e.e.a. anders geïmplementeerd heeft, maar dat betekent ook niet dat je er vanuit mag gaan dat alle implementaties zo werken.
obv test je maar 8 bits, je bool is immers 1 byte storage 
Ik had ook een a == b test, die compiled inderdaad naar 3 instructies ofzo. Punt is, volgens mij gaan &&/|| altijd wel werken, maar een ==/!= niet omdat een compare cheaper is...
volgens mij zou een compiler die standaard C++ zou ondersteunen zoiets doen:
word
maar doen GCC/MSVC eigenlijk
ben niet zeker in hoeverre dit nou echt legaal C++ is
Ik had ook een a == b test, die compiled inderdaad naar 3 instructies ofzo. Punt is, volgens mij gaan &&/|| altijd wel werken, maar een ==/!= niet omdat een compare cheaper is...
volgens mij zou een compiler die standaard C++ zou ondersteunen zoiets doen:
C:
1
2
| bool a, b; bool c = (a == b); |
word
C:
1
| bool c = (a != 0) ^ (b == 0); |
maar doen GCC/MSVC eigenlijk
C:
1
| bool c = ((char)a == (char)b); |
ben niet zeker in hoeverre dit nou echt legaal C++ is
-niks-
Ja, maar op de geteste architectuur is bool ook maar 1 byte groot; de reden dat 'ie als argument 4 bytes groot lijkt is omdat de calling convention vereist dat argumenten op 4-byte-boundaries gealignd worden; de andere bytes zijn dus gegarandeerd nul (of misschien ongedefinieerd? weet niet precies hoe die calling convention gedefinieerd is).Zoijar schreef op zaterdag 06 december 2008 @ 20:40:
Hij kijkt volgens mij ook alleen naar de laagste 8 bits. Dus in dat geval zou dan bv 0xFFFFFF00 == 0x0F0F0F00 == 0x0
edit:
Het enige wat ik er in de standaard over kan vinden is deze voetnoot:
42) Using a bool value in ways described by this International Standard as ‘‘undefined,’’ such as by examining the value of an uninitialized automatic variable, might cause it to behave as if it is neither true nor false.
[ Voor 23% gewijzigd door Soultaker op 06-12-2008 21:34 ]
Ik denk dat het punt is, dat elke assignment aan type bool anders dan "true"/"false"/andere bool een conversie omvat (alle non-null values naar een 1). Op het moment dat ik memset met iets anders als een 1, is het mogelijk om deze behaviour the krijgen:
het zou wel gewerkt hebben als je C++ de conversion laat doen:
Aldus! opgelost!
memset is dus geen valide oplossing, maar werkt in de meeste gevallen wel... Heb ik in elk geval weer iets geleerd...
C++:
1
2
3
4
| bool evil; memset(&evil, 2, sizeof(bool)); bool b1 = evil == true; //false, immers 1 != 2 bool b2 = evil == false; //false, immers 0 != 2 |
het zou wel gewerkt hebben als je C++ de conversion laat doen:
C++:
1
| bool evil = 2; |
Aldus! opgelost!
memset is dus geen valide oplossing, maar werkt in de meeste gevallen wel... Heb ik in elk geval weer iets geleerd...
-niks-
Klopt bijna helemaal. Je mag niet zomaar aannames doen over het bitpatroon van een bool, dus die memset(1,...) vind ik ook verdacht. Aan de andere kant is het wel een POD type, dus memcpy zou wel werken. Maar waarom prutsen? std::fill is inderdaad wat je zoekt. Helder, en de compiler kan naar hartelust optimaliseren.Soultaker schreef op vrijdag 05 december 2008 @ 18:13:
De standaard zegt in ieder geval dat als een integer geïnterpreteert wordt als boolean, nul correspondeert met false en andere waarden met true, maar geldt dat ook voor een bitpatroon dat je in een boolean object kunt schrijven? Dat kan ik me eigenlijk niet voorstellen, want dat betekent dat de compiler er eigenlijk nooit vanuit kan gaan dat een boolean waarde in het geheugen genormaliseerd is naar 1/0 (of twee andere waarden) en dan worden alle vergelijkingen dus een stuk ingewikkelder (en minder efficient).
Je zou memset(1, array, sizeof(array)) kunnen gebruiken, maar eigenlijk moet je dan zeker weten dat true gerepresenteert wordt door 1 én dat booleans precies 1 byte groot zijn; dat laatste is zeker niet altijd het geval.
Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein
Een 'rep stos_' in veel gevallen met primitieven op x86. Heck, ik probeerde laatst voor een micro-optimalisatie een memcpy te implementeren met SSE intrinsics, had ie door dat ik alsnog gewoon geheugen aan het kopieren was dus maakte VC++ daar ook maar een rep movsd vanMSalters schreef op zondag 07 december 2008 @ 02:15:
std::fill is inderdaad wat je zoekt. Helder, en de compiler kan naar hartelust optimaliseren.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
memcpy heeft zelf al een intrinsic form: http://msdn.microsoft.com/en-us/library/tzkfha43(VS.80).aspx
zolang je dus je compilerswitch "Use Intrinsics" aan hebt staan
dat zou stiekum gewoon bij jou het geval kunnen zijn als jouw SSE functie ook memcpy heet, dan gaat ie stiekum toch intrinsics doen en jouw functie negeren. het lijkt me sterk dat de compiler jouw SSE intrinsics gaat negeren en vervangen (dat lijkt me hoe dan ook niet de bedoeling)
zolang je dus je compilerswitch "Use Intrinsics" aan hebt staan
dat zou stiekum gewoon bij jou het geval kunnen zijn als jouw SSE functie ook memcpy heet, dan gaat ie stiekum toch intrinsics doen en jouw functie negeren. het lijkt me sterk dat de compiler jouw SSE intrinsics gaat negeren en vervangen (dat lijkt me hoe dan ook niet de bedoeling)
-niks-
Jeetje, er is nog een hele discussie losgebarsten
. Ik had het probleem eigenlijk al opgelost met memset en dit lijkt prima te werken. Voldoende voor mijn toepassing (programmeeropdracht voor studie).
Docenten zijn meestal wat vergevingsgezinder dan professionals
Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein
Zolang portability geen eis is, maakt het natuurlijk niet echt uit. En tbh, als ik portable code wil schrijven ga ik wel met een VM taal werken, dan hoef je niet/minder met platform bezig te zijn en meer met codenMSalters schreef op zondag 07 december 2008 @ 15:00:
Docenten zijn meestal wat vergevingsgezinder dan professionals
Alleen is het een ramp om een bool die niet true en niet false is te debuggen lijkt me
De enige reden dat ik C++ gebruik is omdat het de standaard is in mijn toekomstige tak van werk, het performance argument van C++ vind ik telkens minder op gaan in vergelijking met bijvoorbeeld C#. Daarnaast is C(++) 1 van de minder doorzichtige talen imo, er zijn heel veel dingen waar je op moet letten die in andere talen niet/nauwelijks aan de orde zijn (bijvoorbeeld, pointers en manual deallocation), er missen wel een aantal features (bijvoorbeeld, reflection of standaard ABI)
Maar goed, het geeft ook wel een soort gevoel van trots om best vloeiend in C++ te zijn
[ Voor 5% gewijzigd door MLM op 07-12-2008 16:26 ]
-niks-
Volgens mijn C++ boek dat ik in de kast heb gegooid nadat ik begonnen ben met C# kan je auto_ptr gebruikenMLM schreef op zondag 07 december 2008 @ 16:25:
[...]
(bijvoorbeeld, pointers en manual deallocation), er missen wel een aantal features (bijvoorbeeld, reflection of standaard ABI)
Semi-offtopic: MSIL (de zooi die van de code overblijft na het compileren) is toch platform-onafhankelijk en niet 64-bit of 32-bit? Maw: Als je C++ libs oproept in de code maakt het toch niet uit of het 64-bit of 32-bit is (zolang het draaiend OS 64-bit is)?
[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]
Dat is ook het idee. Een for-loop waarin je data van de ene array naar de ander kopiëert resulteert in een memcpy(), en de memcpy() resulteert weer in inline asm in de functie als het gebruik van intrinsics (voor die functie) aan staat.MLM schreef op zondag 07 december 2008 @ 10:59:
memcpy heeft zelf al een intrinsic form: http://msdn.microsoft.com/en-us/library/tzkfha43(VS.80).aspx
zolang je dus je compilerswitch "Use Intrinsics" aan hebt staan
Nee, mijn functie heette FastMemCopy()dat zou stiekum gewoon bij jou het geval kunnen zijn als jouw SSE functie ook memcpy heet
Doet ie toch. Een __m128 assignen aan een andere __m128 gaat meestal via een movdqa instructie, die wilde ik dan ook gebruiken. Een hele array van die dingen resulteerde in een rep movsd. Ik moest inline assembly gebruiken om dat te voorkomen.het lijkt me sterk dat de compiler jouw SSE intrinsics gaat negeren en vervangen (dat lijkt me hoe dan ook niet de bedoeling)
De MSIL is idd platform-onafhankelijk, maar de C++ lib niet. En een assembly kan wel aangeven op welke platforms het gerund kan worden. Als je C++ lib dan bijv. 32 bits is, dan moet de assembly dat ook aangeven, anders crasht het keihard op een 64 bits OS.Sebazzz schreef op zondag 07 december 2008 @ 16:37:
Semi-offtopic: MSIL (de zooi die van de code overblijft na het compileren) is toch platform-onafhankelijk en niet 64-bit of 32-bit? Maw: Als je C++ libs oproept in de code maakt het toch niet uit of het 64-bit of 32-bit is (zolang het draaiend OS 64-bit is)?
[ Voor 27% gewijzigd door .oisyn op 07-12-2008 16:57 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Mja, het is een heel andere discussie natuurlijk, maar ik moet nog altijd een overtuigend bewijs zien. Mijn ervaring is dat zelfs VB6 de .Net talen eruit raced.MLM schreef op zondag 07 december 2008 @ 16:25:
De enige reden dat ik C++ gebruik is omdat het de standaard is in mijn toekomstige tak van werk, het performance argument van C++ vind ik telkens minder op gaan in vergelijking met bijvoorbeeld C#.
Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.
Okay, dat had ik niet verwacht. Ik dacht dat intrinsics eigenlijk gewoon assemblerinstructies waren waar de compiler wat context op had en dus kon reorderen/register allocaten, ik wist niet dat ie ze kon/mocht vertalen naar iets anders..oisyn schreef op zondag 07 december 2008 @ 16:50:toon volledige bericht
[...]
Dat is ook het idee. Een for-loop waarin je data van de ene array naar de ander kopiëert resulteert in een memcpy(), en de memcpy() resulteert weer in inline asm in de functie als het gebruik van intrinsics (voor die functie) aan staat.
[...]
Nee, mijn functie heette FastMemCopy()
[...]
Doet ie toch. Een __m128 assignen aan een andere __m128 gaat meestal via een movdqa instructie, die wilde ik dan ook gebruiken. Een hele array van die dingen resulteerde in een rep movsd. Ik moest inline assembly gebruiken om dat te voorkomen.
Ik weet wel dat sommige CRT's (die van Intel bijvoorbeeld) verschillende memcpy's heeft voor verschillende compilatiemodellen (verschillende SSE's), en daar zat volgens mij ook een SSE versie bij die 128 bits verplaatst
Voor zover ik weet krijg je een AssemblyNotFoundException als jouw MSIL een methode referenced (met DllImport attribute bijvoorbeeld) die niet van het juiste type is (MSIL, x86, x64) zodra je iets met de class gaat doen waar die methode aan hangt. Dat is in elk geval wat ik meegemaakt hebt met C#De MSIL is idd platform-onafhankelijk, maar de C++ lib niet. En een assembly kan wel aangeven op welke platforms het gerund kan worden. Als je C++ lib dan bijv. 32 bits is, dan moet de assembly dat ook aangeven, anders crasht het keihard op een 64 bits OS.
-niks-
Neen, af en toe wil de compiler nog wel eens (heel) vreemde dingen doen die eigenlijk helemaal niet nodig zijn. Waarschijnlijk omdat de compiler backend er nog overheen gaat; en die doet net wat meer als register allocation alleen.MLM schreef op zondag 07 december 2008 @ 20:05:
[...]
Okay, dat had ik niet verwacht. Ik dacht dat intrinsics eigenlijk gewoon assemblerinstructies waren waar de compiler wat context op had en dus kon reorderen/register allocaten, ik wist niet dat ie ze kon/mocht vertalen naar iets anders.
Scheelde dat veel? Zou het nog schelen om op die manier naar memory mapped GPU geheugen te copyen?
Het scheelde wel ja, maar ik heb slechts de invloed op m'n app gemeten, niet specifiek de tijd van de copy. Volgens mij maakt het voor write combined mem niet zoveel uit, omdat de MMU de writes toch wel queued en uiteindelijk in bursts uitschrijft. Je hebt natuurlijk wel iets minder overhead tov normale writes (je schrijft in een keer 16 bytes), maar ik weet niet hoe het zich verhoudt tov een rep movsd oid.
[ Voor 24% gewijzigd door .oisyn op 08-12-2008 13:24 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Ik moet een redelijke hoeveelheid texture data vanuit shared memory uploaden (~10MB) en daar heb ik ongeveer 4ms voor. Nu haal ik met PBOs/memory mapped GPU geheugen een 2.5GB/s upload rate (pcie 1.1). Elke ms dat het sneller zou zijn is een grote performance gain. Ik Zou het eens kunnen proberen, maar ik weet niet of het uitmaakt. Volgens mij is toch de pcie bus de bottleneck..oisyn schreef op maandag 08 december 2008 @ 13:23:
Het scheelde wel ja, maar ik heb slechts de invloed op m'n app gemeten, niet specifiek de tijd van de copy. Volgens mij maakt het voor write combined mem niet zoveel uit, omdat de MMU de writes toch wel queued en uiteindelijk in bursts uitschrijft. Je hebt natuurlijk wel iets minder overhead tov normale writes (je schrijft in een keer 16 bytes), maar ik weet niet hoe het zich verhoudt tov een rep movsd oid.
Is het ook puur en alleen een copy van 1 lineaire buffer, of schrijf je ondertussen ook andere data naar ander mem weg? Want IIRC flushen de WC buffers bij een write naar niet-WC mem, en je hebt ook maar een gelimiteerd aantal WC buffers (bijv. 3 op Intel Netburst cpu's, dus als je dan 4 rijen pixels tegelijk schrijft dan veroorzaak je steeds onnodige flushes)
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Nee, ik doe het heel straight-forward nu. Zoiets:.oisyn schreef op maandag 08 december 2008 @ 13:51:
Is het ook puur en alleen een copy van 1 lineaire buffer, of schrijf je ondertussen ook andere data naar ander mem weg? Want IIRC flushen de WC buffers bij een write naar niet-WC mem, en je hebt ook maar een gelimiteerd aantal WC buffers (bijv. 3 op Intel Netburst cpu's, dus als je dan 4 rijen pixels tegelijk schrijft dan veroorzaak je steeds onnodige flushes)
offset = 0
for n in nr_textures on GPU
pointer = map pbo for texture n
memcpy(pointer, shared_mem + offset, size texture n in bytes);
offset += size texture n
(en dan een stuk of 6 textures van ~1.5MB each)
[ Voor 3% gewijzigd door Zoijar op 08-12-2008 14:47 ]
Pagina: 1