- Onwards and upwards - 2 Updates
- gcc libatomic "sample library" - 1 Update
- Poor Mans RCU... - 1 Update
- #include'ing .c files considered harmful? - 21 Updates
Mr Flibble <flibble@i42.REMOVETHISBIT.co.uk>: Feb 14 10:58PM On 14/02/2021 22:56, Brian Wood wrote: > Brian > Ebenezer Enterprises > https://github.com/Ebenezer-group/onwards You might as well be a bot with that reply, fucktard. /Flibble -- 😎 |
David Brown <david.brown@hesbynett.no>: Feb 15 01:15AM +0100 On 14/02/2021 23:56, Brian Wood wrote: >> checked by no one is merely part of the daily grind for a coder. > Perhaps we can at least agree that services are the most important > form of software today Absolutely not, no. I don't really think it makes sense to talk about "the impost important form of software" - our way of life depends on a wide variety of software types. But if I had to pick one, it would be embedded software - the kind that most people never see, and never think about, but makes things work. Online code generators would rank down at the bottom of the list - they are not necessary in any way. They might sometimes be convenient, but they are not important. > and that C++ is the most important language > for services. Again, no. Most online services are written in other languages. C++ is not the worst choice (it's far better than C) for that kind of thing, but it is not a great choice either. >> harder sell for most potential code reviewers. > A lot of code review is done for free: > https://www.reddit.com/r/codereview Sure - for free projects. No one does code reviews for free for commercial products. Why do you think people should review /your/ code for free? > for articles of silver and gold, and for clothing. And the L-RD gave the > people such favor in the sight of the Egyptians that they granted their > request. In this way they plundered the Egyptians." Exodus 12:36,37 I'm sorry, I can't see what relevance there is in quoting an old story book. > The Israelites didn't pay for the items of gold and silver. G-d was > saving them from their oppressors. Unfortunately, some of the > regulars here are oppressors. No one here is oppressing /people/ - certainly not oppressing Christians, Jews, Israelites, Egyptians, or any other particular religion or nationality. People /do/ oppress preaching or pointless, off-topic and repetitive religious posts. Stick to the topic at hand. |
Marcel Mueller <news.5.maazl@spamgourmet.org>: Feb 13 08:42PM +0100 Am 13.02.21 um 15:56 schrieb David Brown: >> value. > Yes, that could perhaps be a way to handle things, but off the top of my > head I can't see how to do this safely and generically. This is quite easy. you only need two physical storage for the data. One holds the current value, one the next value. When you synchronize only writers they can safely swap the storage pointer. No need to synchronize readers. Often that's enough. Even more sophisticated solutions may use thread local storage for the values. Each thread has a current and a next storage. This removes the need for the writer mutex. In case of an IRQ handler (which usually is not re-entrant) dedicated storage for the IRQ handler could do the job. If this is still not sufficient because the high update rate could cause a reader to get two versions behind the stolen bits hack in the referring pointer may identify this situations. Readers need to increment the master pointer atomically before using the storage it points to. Now writers know that they should not discard or modify this storage. >> If a generic atomic library does not guarntee forward progress when used >> with different priorities it is not suitable for this case. > All RTOS systems are sensitive to priority inversion, Sure, but lock free algorithms are not. ;-) > for even the simple situation of having a 64-bit value shared between an > interrupt function and a main loop or other thread - it will kill your > system if there is an access conflict. Is it possible to raise the priority of all mutex users for the time of the critical section? This will still abuse a time slice if the spin lock does not explicitly call sleep. But at least it will not deadlock. Marcel |
Jorgen Grahn <grahn+nntp@snipabacken.se>: Feb 14 08:12PM On Sun, 2021-02-14, Chris M. Thomasson wrote: > On 2/13/2021 4:54 AM, Jorgen Grahn wrote: >> On Tue, 2021-02-09, Chris M. Thomasson wrote: ... >> At least on Unix (where the whole output/error stream thing comes >> from). > I don't know if that's guaranteed. I think it is, but it would be nice to have it confirmed. I think I can quote W R Stevens, but he only writes about Unix. If the people with the problems e.g. ran the code in an IDE, that would explain it. Or piped the output through less(1). /Jorgen -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o . |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Feb 16 11:24PM On Tue, 16 Feb 2021 23:25:43 +0100 > defined, because some people think it is? Should you add checks for > pointers being non-zero before dereferencing them, because some people > get it wrong and many of the checks can be optimised away? Yes, but by the same argument should you make the language incrementally more difficult to use with every new memory feature: honestly, what percentage of C++ programmers have even heard of std::launder? But if you want to construct an array in malloc'ed or 'new char'ed memory and access it again from your original pointer you better have had. I have to confess I have started to steer away from C++ for new projects, not because I fail to understand it, but perhaps because I understand it too well. I think it is getting its trade-offs wrong. (I also think that the standard is not curated adequately as witness the contents of http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p0593r6.html which corrected C++17 for C++20 by some last-minute messing about with ISO procedures: between 2017 and 2020 best practices used by the best programmers for years were technically defective - even std::uninitialized_copy had, but its own rules, undefined behaviour.) I think times have moved on. > defining a pointer provenance model for C and C++, to improve alias > tracking (for knowing when apparently different pointers may alias, and > for being sure that pointers of similar types do not alias). Casting is not necessarily lying to the computer. It is only lying to the computer if an object of the relevant type does not in fact reside at the memory in question. (Even if it does, that doesn't mean you can get away without using std::launder. And that de-optimizer is not required just for writing allocators.) |
James Kuyper <jameskuyper@alumni.caltech.edu>: Feb 16 10:54PM -0500 > On Mon, 15 Feb 2021 15:54:36 -0500 > James Kuyper <jameskuyper@alumni.caltech.edu> wrote: ... >> memory, or if you copied it over as an array of character type, that >> memory acquires the same effective type as the object it was copied from. > Memory is memory, it doesn't have a type. The C standard says otherwise, and so does the C++ standard. That type is kept track of by the compiler, not by the hardware, but it does have a type. That type is very important - how and when the effective type of a piece of memory changes determines which optimizations a compiler can perform. If a compiler performs an optimization that is permitted by those rules, and your code breaks those rules, there's a significant chance (but no guarantees) that you won't be happy with the resulting behavior. > ... How the compiler sees it is another > matter of course but unless a C/C++ compiler wants to break a huge amount of > code its going to have to treat memory in this instance as void. That would make things very easy - dereferencing a pointer to void has undefined behavior. If they did that, they wouldn't have to worry about type-punning at all; for practical purposes, that means that they wouldn't support type punning. I suspect you meant something else by that statement. >> anti-aliasing rule: > Fine, but like it or not type punning has been de facto standard C for a very > long time and any C compiler (and C++ in many cases) breaks it at its peril. Most C compilers do in fact enable optimizations that are permitted only because of the anti-aliasing rules, and can therefore cause your program to fail if you write code that violates those rules. It's not guaranteed to, but it can. They perform those optimizations because developers like to see their code execute faster. That those optimizations make it somewhat trickier to write correct code is a price that many developers are willing to pay. If you want to ignore such issues, don't write your code in C (or C++). Use some other language that protects you from having to worry about them. >> that union is in scope at the point where the problem could otherwise occur. > Unions are another matter entirely mainly because endianess issues tend to > occur with them regardless of memory alignment. Unions are very much the same matter - almost every use of a union to perform type punning would have undefined behavior according to the anti-aliasing rules, if it weren't for the fact that the C standard says otherwise. If read one member of a union is sequenced after a write to a different member, with no other writes that are either sequenced betweent them or unsequenced relative to them, the the write will be completed before the read, and the read will result in the bit pattern created by that write being interpreted as if it were an object of the type used to read it (this can be problematic if that bit pattern doesn't represent a valid value of that type, but is otherwise well-defined behavior). Those guarantees do not normally apply when the type written and the type read do not satisfy the anti-aliasing rules. Note: these are C rules, the C++ rules are stricter on this issue. > IME most compilers when pushed to do heavy optimisation start making subtle > mistakes here and there. Any heavily optimised code should always be tested > much more thoroughly than non optimised before its released. I suspect that if you were not already aware of this issue, then it's possible that the "mistakes" you've seen might have been perfectly legitimate optimizations, permitted as a result of violations of this rule, or possibly of other similar rules that you're also unaware of. I'm not saying that compilers are always right. I'm just saying that if you aren't aware of how to write your code to avoid violating the anti-aliasing rules, there's probably many other rules that you also don't know how to avoid violating. |
James Kuyper <jameskuyper@alumni.caltech.edu>: Feb 16 11:06PM -0500 On 2/16/21 5:47 AM, David Brown wrote: ... > Type punning is possible in a variety of ways. But the standards do > /not/ allow it just by doing pointer casts. Accessing memory by an > incompatible type breaks strong typing. We are talking about the C standard, for which "compatible type" has a very specific meaning (see section 6.2.7 of the C standard). "a type compatible with the effective type of the object" is only the first of the six different cases where type punning is permitted - the other five cases all involve types that are incompatible with the effective type. C++ uses the concepts of "layout-compatible types" and "reference-compatible types", but the only types it refers to as simply "compatible" are pointer types (20.3.11p6). |
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Feb 16 08:20PM -0800 > On 2/16/21 4:47 AM, mickspud@potatofield.co.uk wrote: [...] > type-punning at all; for practical purposes, that means that they > wouldn't support type punning. I suspect you meant something else by > that statement. Dereferencing a pointer to void is a constraint violation, and I'd be surprised to see a compiler that didn't treat it as a fatal error. There's no undefined behavior if there's no behavior. Though I suppose the (run-time) behavior would be undefined if a compiler permitted it for some reason. -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com Working, but not speaking, for Philips Healthcare void Void(void) { Void(); } /* The recursive call of the void */ |
James Kuyper <jameskuyper@alumni.caltech.edu>: Feb 16 11:24PM -0500 On 2/16/21 11:20 PM, Keith Thompson wrote: >> wouldn't support type punning. I suspect you meant something else by >> that statement. > Dereferencing a pointer to void is a constraint violation, You're right. My mistake. |
"Öö Tiib" <ootiib@hot.ee>: Feb 16 11:45PM -0800 On Wednesday, 17 February 2021 at 00:25:56 UTC+2, David Brown wrote: > defined, because some people think it is? Should you add checks for > pointers being non-zero before dereferencing them, because some people > get it wrong and many of the checks can be optimised away? Programmers are expected to be users of tool. Tool has to be specified with usability in mind. Tool that is harder and harder to use is losing its usages. The C++ committee understood it two decades ago. For little example they realized after C++98 that programmers use container.size() == 0 more frequently than container.empty() for detecting if container is empty and so required size() of all container types to be O(1), despite it made some containers slightly less efficient. By C++17 that attitude did die off and unsure if it ever comes back. The checks are often done on level of hardware architecture to support other, more checked languages and so are technically free unless failing. C++ does not promise any of those common free checks and instead allows optimizing clumsily written explicit checks away ... so those are symptoms of sabotaged tool. All those std::launders, std::byte full of UBs that unsigned char did not have, broken constexpr. Pure trash. |
mickspud@potatofield.co.uk: Feb 17 09:03AM On Tue, 16 Feb 2021 22:54:27 -0500 >> Memory is memory, it doesn't have a type. >The C standard says otherwise, and so does the C++ standard. That type >is kept track of by the compiler, not by the hardware, but it does have As I said below. >That would make things very easy - dereferencing a pointer to void has Good luck with that. >> Unions are another matter entirely mainly because endianess issues tend to >> occur with them regardless of memory alignment. >Unions are very much the same matter - almost every use of a union to Yes I know, do try and understand idiom. >you aren't aware of how to write your code to avoid violating the >anti-aliasing rules, there's probably many other rules that you also >don't know how to avoid violating. I'm getting tired of this patronising crap from pedants. I've NEVER seen type punning fail so long as pragmas were used correctly regardless of optimisation but if any of you can provide a simple example where it does then feel free to post it instead of a lot of hand waving vagueries and appeals to "the standard". |
David Brown <david.brown@hesbynett.no>: Feb 17 11:57AM +0100 On 17/02/2021 00:24, Chris Vine wrote: >> get it wrong and many of the checks can be optimised away? > Yes, but by the same argument should you make the language incrementally > more difficult to use with every new memory feature: A language needs to figure out where it stands on this kind of thing at an early stage, and when stabilising. Then it should stick to the decisions it makes unless there is a very good reason to do otherwise. Once you have a base of existing code in use, it's hard to make changes at this level. If you remove semantics to allow more optimisation, you break code that used to be correct according to the language specification when it was written. If you add semantics and reduce optimisation, code that was fine before now runs less efficiently. Neither is good. (An example of where changes have been justified are the C++17 additional rules for the sequencing of sub-expressions. The new rules are needed to make some clear and common stream expressions valid, while being very unlikely to lead to any extra run-time cost for existing code.) > percentage of C++ programmers have even heard of std::launder? But if > you want to construct an array in malloc'ed or 'new char'ed memory and > access it again from your original pointer you better have had. That would count as making your own allocator. You are defining your block of memory as one type, and then accessing it as a different type - it is not unreasonable that you need extra code to tell the compiler about it. (I'd prefer it if the language mechanics made it a compile-time error to fail to get this right.) Other uses for std::launder are if you are using placement new to change an object that is defined with "const". When you define something as "const", you are telling the compiler that it cannot change value (merely declaring it as "const" says that you won't change its value via that declaration). The compiler can optimise on the assumption that the const object won't change value. And then you use placement new and change it. So you need std::launder to inform the compiler of the change. These are not things that come up often, in normal code. C++ is full of obscure and difficult features that are only needed and known by a relatively small number of people. This is, I think, a necessarily evil for big languages. (Look at Python - how many people can tell you how "__slots__" should be used to make code more efficient? How many can explain metaclasses?) > to confess I have started to steer away from C++ for new projects, not > because I fail to understand it, but perhaps because I understand it > too well. I think it is getting its trade-offs wrong. That's possible. It's always difficult to distinguish "wrong" from "not what I want", but if enough existing C++ users think it is "not what I want", then it becomes "wrong". > at the memory in question. (Even if it does, that doesn't mean you can > get away without using std::launder. And that de-optimizer is not > required just for writing allocators.) Fair enough - casting itself is not lying to the compiler. But many uses of the result of the cast are lies. |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Feb 17 01:50PM On Wed, 17 Feb 2021 11:57:36 +0100 > On 17/02/2021 00:24, Chris Vine wrote: [snip] > it is not unreasonable that you need extra code to tell the compiler > about it. (I'd prefer it if the language mechanics made it a > compile-time error to fail to get this right.) I disagree. Constructing arrays dynamically in uninitialized memory is a very common requirement. Making your own buffer is not making your own allocator and I think it is completely wrong to describe it as such. Converting sound code written prior to 2017 which does this very common thing into undefined behaviour without std::launder is in my opinion (I accept not yours) unacceptable. |
James Kuyper <jameskuyper@alumni.caltech.edu>: Feb 17 09:34AM -0500 >> On 2/16/21 4:47 AM, mickspud@potatofield.co.uk wrote: >>> On Mon, 15 Feb 2021 15:54:36 -0500 >>> James Kuyper <jameskuyper@alumni.caltech.edu> wrote: <Restore snipped context> >>> ... How the compiler sees it is another >>> matter of course but unless a C/C++ compiler wants to break a huge amount of >>> code its going to have to treat memory in this instance as void. </restore snipped context> ...>> That would make things very easy - dereferencing a pointer to void has > Good luck with that. "treat memory in this instance as void" would not avoid breaking a huge amount of code - it would break all code that qualifies as "in this instance", for precisely the reason you are expressing by saying "good luck with that". Whatever it is that you meant by that phrase needs to be expressed differently. What precisely is "this instance"? I'm having trouble interpreting your comments in any fashion except as insisting that type-punning should always be handled as reinterpreting the bit-pattern, the same way that unions do. If you are instead saying only that there should be some additions to the list of exceptions to the anti-aliasing rule, that would be much more workable. |
mickspud@potatofield.co.uk: Feb 17 02:42PM On Wed, 17 Feb 2021 09:34:13 -0500 >What precisely is "this instance"? I'm having trouble interpreting your >comments in any fashion except as insisting that type-punning should >always be handled as reinterpreting the bit-pattern, the same way that What have bit patterns got to do with it? I'll I'm saying is if I cast from one pointer type to another the resulting pointer has the same memory address and I'm trying to think in what circumstances it wouldn't. I've asked for an example and no one has provided one. |
Bo Persson <bo@bo-persson.se>: Feb 17 03:53PM +0100 > from one pointer type to another the resulting pointer has the same > memory address and I'm trying to think in what circumstances it > wouldn't. I've asked for an example and no one has provided one. You have the case of multiple base classes, where casting to anyone but the first base will give you a different address. And casting a char pointer to an int pointer, while preserving the address, might give you an invalid (unaligned) pointer. |
mickspud@potatofield.co.uk: Feb 17 03:25PM On Wed, 17 Feb 2021 15:53:08 +0100 >> wouldn't. I've asked for an example and no one has provided one. >You have the case of multiple base classes, where casting to anyone but >the first base will give you a different address. Ok, I didn't know that, but then taking the raw address in that situation is probably never something you're going to do in practice. >And casting a char pointer to an int pointer, while preserving the >address, might give you an invalid (unaligned) pointer. AFAIK that doesn't matter on x86, can't remember ever seeing a bus error on Linux. But obviously it does on other architectures. |
David Brown <david.brown@hesbynett.no>: Feb 17 04:45PM +0100 > Ok, when I said essential I meant for efficient coding. Obviously you can > always use other methods and for [reasons] you prefer memcpy. It seems to boil > down to personal choice and there's little point arguing over that. As I explained, memcpy (used appropriately and with a decent compiler, such as reasonably current gcc) has /zero/ run-time cost. The same often (but not always) applies to accessing data via unsigned char pointers and building up the composite data that way. Those are valid techniques for accessing "weird" layouts - data with unusual alignments, data with unusual sizes (like a 24-bit integer), data with non-native endianness. Done well in wrapping functions, classes, templates or macros, it does not even have to be difficult to use or ugly in the source code. And done well, the results are optimal efficiency on good tools, while being guaranteed correct on other tools regardless of optimisation flags or other settings. That of course does not mean that this is /always/ the best way to write the code. It does not mean that it will give you optimal results with all compilers. But in my book, /correctness/ trumps efficiency every time. If you know you are using a single fixed compiler and fixed target, and you know the effect of a particular extension, and you know the additional semantic guarantees the tool gives you, then of course it can be better to use these extensions. I do that myself in a lot of my code - if I am dealing with endian issues, I will sometimes use gcc's "scaler_storage_order" attribute rather than "hton*" or manual byte swaps. But do you /need/ to use "pragma pack" to get efficient code from structs with odd alignment? No, you most certainly do not. Do you need to use pointer casts and use them in ways not defined in the C standards? No, you most certainly do not - not with decent tools. However, sometimes you /don't/ have a good compiler and you are faced with a choice of writing technically correct code that is slow, or technically incorrect code that you can see works in this particular case. That's part of life as a programmer. My recommendation for that kind of situation is pre-processor checks for the compiler you know and have tested for the non-portable but efficient code, either with a fall-back to a portable but potentially slow alternative, or simply giving compilation failure when the code is used on a different tool. That attitude improves code re-use and reduces the risk of accidents. |
scott@slp53.sl.home (Scott Lurndal): Feb 17 03:58PM >>address, might give you an invalid (unaligned) pointer. >AFAIK that doesn't matter on x86, can't remember ever seeing a bus error on >Linux. But obviously it does on other architectures. X86 will fault unaligned accesss if the AF flag is set in the cpu flags. Linux generally doesn't set that flag. |
scott@slp53.sl.home (Scott Lurndal): Feb 17 04:00PM >> down to personal choice and there's little point arguing over that. >As I explained, memcpy (used appropriately and with a decent compiler, >such as reasonably current gcc) has /zero/ run-time cost. Except for any cache line(s) evicted as a result of the memcpy, which may indeed have an overall performance cost. |
Manfred <noname@add.invalid>: Feb 17 05:20PM +0100 On 2/16/2021 10:35 PM, Chris Vine wrote: > obscure technical rules launched at programmers because a compiler > vendor has asserted that it might make 1% of code 0.5% faster seems to > me to be the wrong balance. Valid point. std::launder is IMO a good example of bad design. |
James Kuyper <jameskuyper@alumni.caltech.edu>: Feb 17 11:22AM -0500 > from one pointer type to another the resulting pointer has the same > memory address and I'm trying to think in what circumstances it > wouldn't. I've asked for an example and no one has provided one. No one is suggesting that the pointer would point to a different memory address (though that is in fact a potential problem in some cases - see below). They're saying that you cannot safely use the pointer that results from the conversion to access the memory it points at. Implementations are allowed to perform optimizations that ignore the possibility that two pointers to different types might point at the same location in memory, depending upon what relationships those two types have to each other. With regards to the "same memory address": conversion of a pointer to one type into a pointer to a different type which has alignment requirements violated by the original pointer has undefined behavior, which in particular allows for the possibility that the resulting pointer does not point at the same memory location. As an example of the reason why this rule exists, there have been implementations targeting machines with large word sizes which have pointers to word-aligned types that have fewer bits (and even, in some cases, fewer bytes) than pointers to types with smaller alignment requirements. Conversion of a pointer that doesn't point at the beginning of a word to a pointer type that can only represent positions at the beginning of a word CANNOT result in a pointer to the same location. <pedantic>Even when pointer conversions have defined behavior, in general that definition only says that if the resulting pointer value gets converted back to the original pointer type, it will compare equal to the original. There are subtle differences between the C and C++ standards about these issues, but neither standard specifies where the resulting pointer points except in some special cases. Personally, I think they should specify that it points at the same location, but they don't. The C exceptions are easier to describe, so I'll list them here: 1. converting a pointer to an array into a pointer of the element type of the array results in a pointer pointing at the first element of the array. 2. Converting to a pointer to a struct type into a pointer to the pointer to the type of the first member of the struct results in a pointer to that member. 3. Conversion of a pointer to a pointer to character type results in a pointer to the first byte of the object. Each of these conversions are reversible. </pedantic> |
David Brown <david.brown@hesbynett.no>: Feb 17 05:30PM +0100 On 17/02/2021 17:00, Scott Lurndal wrote: >> such as reasonably current gcc) has /zero/ run-time cost. > Except for any cache line(s) evicted as a result of the memcpy, which > may indeed have an overall performance cost. #include <inttypes.h> // for int32_t related stuff #include <string.h> #pragma pack(1) typedef struct S { int8_t a; int32_t b; int64_t c; } S; int getsize(void) { return sizeof(S); } int32_t getb1(const S* p) { return p->b; } int32_t getb2(const S* p) { int32_t x; memcpy(&x, &p->b, sizeof x); return x; } int32_t getb3(const S* p) { const uint8_t * q = (const uint8_t *) &p->b; int32_t x; uint8_t b[sizeof x]; for (size_t i = 0; i < sizeof x; i++) { b[i] = *q++; } memcpy(&x, b, sizeof x); return x; } int32_t getb4(const S* p) { const uint8_t * q = (const uint8_t *) (&p->b + 1) - 1; int32_t x = 0; #pragma GCC unroll sizeof x for (size_t i = 0; i < sizeof x; i++) { x = (x << 8) | *q--; } return x; } gcc (via godbolt.org) on x86-64 with -O2 gives: getb1: movl 1(%rdi), %eax ret getb2: movl 1(%rdi), %eax ret getb3: movl 1(%rdi), %eax ret getb4: movl 1(%rdi), %eax ret Exactly which cache lines are "evicted" by the use of memcpy here? |
mickspud@potatofield.co.uk: Feb 17 05:12PM On Wed, 17 Feb 2021 11:22:36 -0500 >requirements. Conversion of a pointer that doesn't point at the >beginning of a word to a pointer type that can only represent positions >at the beginning of a word CANNOT result in a pointer to the same location. Really? gondor$ cat t.c #include <stdio.h> #include <stdint.h> int main() { char s[5]; uint32_t *i = (uint32_t *)s; *i = 123; printf("addr = %p, val = %u\n",i,*i); return 0; } gondor$ cc t.c gondor$ a.out addr = 0x7ffe017f3873, val = 123 That int looks nonaligned to me. |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Feb 17 05:28PM On Wed, 17 Feb 2021 16:00:14 GMT > >such as reasonably current gcc) has /zero/ run-time cost. > Except for any cache line(s) evicted as a result of the memcpy, which > may indeed have an overall performance cost. Wherever a reinterpret_cast wouldn't have alignment issues, memcpy will be optimized out entirely - it is a compiler intrinsic/built-in. (In fact, in C++17 it has to be an intrinsic because memcpy cannot be implemented as a function using standard C++17 without undefined behaviour, but that is a bug in the standard rather than a feature.) |
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment