Skrivet av klk:
Intel och MinGW är de jag vet om, vet inte om man skall räkna MinGW som en egen men skall man kompilera och efterlikna GCC på windows tror jag det är den som används.
C++ är extremt komplext och där är det inte så många men det är mer än i andra språk
C har du säkert över 100 olika kompilatorer
Som jag förstått det lade Intel i praktiken ned sin egen kompilator 2021, istället jobbar man med att få in motsvarande optimeringar i LLVM.
https://www.phoronix.com/news/Intel-LLVM-Adoption-C-CPP
MinGW är en Windows port av GCC. "Vanliga" GCC är bara designad för *NIX.
Men det finns ett par till C++ kompilatorer till. Den jag känner bäst till är DIAB som länge var den bästa kompilatorn för PowerPC, idag är fokus där primärt på områden för certifiering och det primärt för ARM64 och x64.
Skrivet av klk:
Den här typen av kod är inte rolig i C++ men det är en mardröm och få till det i andra språk
arguments& arguments::append(const char* pbszName, uint32_t uNameLength, argument_type uType, const_pointer pBuffer, unsigned int uLength)
{ assert(m_pbuffer->get_reference_count() <= 1); assert( uNameLength < 0x1000 ); // no change if two or more holds value and realistic name lenghts
#ifndef NDEBUG
enumCType eType_d = (enumCType)(uType & ~eTypeNumber_MASK); // get absolute variable type
auto typename_d = gd::types::type_name_g( eType_d ); // readable name for type
#endif // _DEBUG
// ## calculate needed size to make sure internal buffer is large enough
uint64_t uReserveLength = buffer_size(); // current buffer size
/// ### [name type and nanme lenghth][name value]{value type and value buffer length]{native value length}[value data] = total byte count needed to store value
uReserveLength += uNameLength + sizeof( uint32_t ); // name if any and length value for name
uReserveLength += uLength + sizeof(uint32_t); // value length (and prefix value length for strings)
uReserveLength += sizeof(uint32_t) * 2; // padding space to enable space for 32 bit alignment (name and value is aligned)
uReserveLength = align32_g( uReserveLength ); // align
// reserve data for name, length for name, name type, data type and data value
// uReserveLength should be enough for -> [name type][name length][name text][value type]{native value length}[value data]
reserve( uReserveLength );
auto uPosition = buffer_size(); assert( uPosition % 4 == 0 );
#ifndef NDEBUG
auto uBegin_d = uPosition; // keep position to check total length for value in debug
#endif // _DEBUG
auto pdata_ = buffer_data();
uint32_t uTypeAndSize = (eType_ParameterName << 24) | uNameLength;
*(uint32_t*)(pdata_ + uPosition) = uTypeAndSize; // set name type
uPosition += sizeof( uint32_t ); // move past key type and length (stored in 32 bit value)
memcpy(&pdata_[uPosition], pbszName, uNameLength); // copy name
uNameLength = align32_g( uNameLength ); // align if needed
uPosition += uNameLength; // add length for name
assert( uPosition % 4 == 0 );
if( (uType & eValueLength) == 0 ) // if type doesn't have specified length flag then just copy data into buffer
{
uint32_t uValueLength = uLength;
uLength = align32_g( uLength ); // align to 32 bit boundary
uTypeAndSize = (uType << 24) | uLength;
*(uint32_t*)(pdata_ + uPosition) = uTypeAndSize; // set type and size
uPosition += sizeof( uint32_t );
memcpy(&pdata_[uPosition], pBuffer, uValueLength); // copy value data
uPosition += uLength; // add aligned length
buffer_set_size( uPosition ); assert(buffer_size() < buffer_buffer_size());
}
else
{
uint32_t uValueLength = uLength; // value length in bytes (storage needed to hold data)
uLength += sizeof( uint32_t ); // add value length to total value size
uLength = align32_g( uLength ); // align to 32 bit boundary
uTypeAndSize = (uType << 24) | uLength; // set value type and length in 32 bit value
*(uint32_t*)(pdata_ + uPosition) = uTypeAndSize; // set type and size
uPosition += sizeof( uint32_t ); // move past type and size
uint32_t uCompleteType = gd::types::typenumber_to_type_g( uType & ~eType_MASK );// get the full type information from gd types to investigate the object length
// ## fix size to the actual length for value, this is to improve the speed
// generating value objects from data
if(uCompleteType & gd::types::eTypeGroupString)
{
if(( uType & eTypeNumber_MASK ) == eTypeNumberWString)
{ assert( (uValueLength % 2) == 0 );// make sure unicode is correct
uValueLength = uValueLength >> 1; // unicode string, length is cut in half
}
}
*(uint32_t*)(pdata_ + uPosition) = uValueLength;
memcpy(&pdata_[uPosition + sizeof( uint32_t )], pBuffer, uLength); // copy data
uPosition += uLength; // move past data for value (length and data)
buffer_set_size( uPosition ); assert(buffer_size() < buffer_buffer_size());
}
#ifndef NDEBUG
auto uValueSize_d = uPosition - uBegin_d; // total size needed for value in `arguments` object
#endif // _DEBUG
return *this;
}
Dold text
Du har postat ett i stort sätt samma exempel här
#20783543
finns inget i någon av de två exemplen som inte kan göras rätt mycket exakt lika effektivt i Rust, Go, C#, m.fl. Du fick ett exempel i Rust här
#20783605
Skrivet av klk:
Korrekt.
Jämför med att tävla i exempelvis köra så snabbt som möjligt runt en formula 1 bana.
Sätter du dig i en volvo går det inte lika snabbt som om du kör en Formula 1 bil. Det är däremot säkrare
En formula 1 bil är inte konstruerad för att vara trygg, den är optimerad för att så snabbt som möjligt ta sig runt
Förutom att billiknelser sällan blir perfekta har du här fått flera konkreta beskrivningar varför det inte alls är säkert att C++ ger snabbast/mest effektiva kod längre (ignorerat att man handhackar i assembler, men då är det inte C++ längre).
C++ största värde är dess ålder kombinerat med att det länge, ihop med C, rätt mycket var det enda språk med bra stöd för att skriva högpresterande programvara om man ville slippa sitta med assembler. Mycket vatten har runnit under broarna och väldigt mycket har förändrats rätt fundamentalt sedan C++ introduktion i mitten av 80-talet och dess standardisering med början på 90-talet.
Vissa designval i C++ kan inte ändras med mindre än att paja bakåtkompatibilitet. Vissa av dessa val gör att moderna kompilatorer kan i vissa lägen göra fler optimeringar i mer moderna språk. Att minimera antalet CPU-instruktioner är inte heller alls lika viktigt idag som på 80/90-talet.
Idag kan man nästan tänka "alla instruktioner tar 0 cykler, förutom när man missar cache och måste gå mot RAM då det tar 100-tals cykler att köra en instruktion". Och det är när man ändå fortfarande kör sina tunga beräkningar på CPU, vi ser allt fler av de riktigt "compute-bound" lasterna allt mer hanteras av specialkretsar som GPU, NPU, etc. Ett väldigt målande exempel på det är machinelearning där det inte spelar någon roll att man sitter i Python, det är ändå snabbare än vad någon skulle få ihop med ett CPU-only C++ bibliotek då detta är något som är långt snabbare på GPU så fort problemet blir "tillräckligt stort".
C++ kanske är en 80-tals F1 bil, men det finns idag touring bilar där man får säkerheten av ett tak, en större cockpit men som ändå kan köra minst lika snabbt, i.e. Rust
Sen finns ju andra fall som Go, ISPC, etc om banan inte råkar vara en F1-bana utan kanske en street-bana där F1 bilen kommer få problem vid första större ojämnhet i vägen...
Skrivet av klk:
Att vuxna människor har problem med någon säger att prestanda är viktigt för C++ programmerare, alltså jag vet inte hur jag skall tolka det. (en av egenskaperna som är viktigt för C/C++)
Fast är det någon som säger det i denna tråd?
Har själv använt C++ väldigt mycket genom åren. Senaste ~5 åren har det i praktiken bara innefattat legacy-fall, i.e. jag har jobbat med C++ "för jag har väldigt mycket erfarenhet av C++, så tenderar bli inslängd i sådana projekt". Men ser inte längre någon anledning alls att idag välja C++ för ett green-field eller ens brown-field projekt då det finns bättre alternativ för alla use-case jag kan tänka mig.
Orsakerna att använda C++ idag är innefattar absolut "prestanda är viktigt", majoriteten av legacy-projekt som använder C++ gör det väldigt ofta p.g.a. detta. Men har man förmånen att starta från scratch idag finns andra alternativ som är enklare, som i praktiken kommer ge minst lika bra prestanda (ta Go som p.g.a. av sin unika runtime-miljö är långt enklare att hantera storskaliga I/O-tunga jobb jämfört med C++, bästa C++ kan göra är kopiera detta så gott det går för att ge legacy-kod en liknande möjlighet även om den är gisigare/krångligare och inte nödvändigtvis lika effektiv).
Och idag är det viktigare att utnyttja saker som parallellism (beroende på problem så kan det vara multicore och/eller SIMD) och i allt större utsträckning olika former av acceleratorer. Se på t.ex. Blender och PyTorch, spelar ingen roll hur mycket C++-optimeringar du stoppar in även med den snabbaste CPU du hittar, det kommer ändå vara heltalsfaktorer snabbare på en GPU även om CPU-delen av programmet körs i Python!