- sizeof(bitfield struct) - 7 Updates
- How to print instances of my classes - 1 Update
- How to print instances of my classes - 5 Updates
- What does operating on raw bytes mean in a C++ context? - 2 Updates
- spurious warning? - 1 Update
David Brown <david.brown@hesbynett.no>: Nov 06 04:08PM +0100 On 06/11/18 15:49, Rick C. Hodgin wrote: > size in bytes, and the bitsizeof() to return the size in bits, and > that will be globally, not just on bitfield structs or members. > Good day, David. Adding a "bitsizeof" operator for bit-fields seems reasonable enough. I don't see a lot of potential use for it, but I know we have very different opinions on that sort of thing (I want to know a feature is very useful before adding it, you prefer to add early and let the user decide if they want to use it). |
"Rick C. Hodgin" <rick.c.hodgin@gmail.com>: Nov 06 07:32AM -0800 On Tuesday, November 6, 2018 at 10:08:16 AM UTC-5, David Brown wrote: > different opinions on that sort of thing (I want to know a feature is > very useful before adding it, you prefer to add early and let the user > decide if they want to use it). Yes, because I'm not arrogant enough to think I have all the answers to all of the coding scenarios. I want to empower each developer to be able to reach into the vast tookbox and use the tools they need. People who trim trees drive similar trucks to those who install power lines, cable and Internet, yet I bet each of those trucks that look outwardly similar have vastly different tools in the toolboxes. For different types of application design, it's like that. Some trim trees, some install power lines, and some work with the el- ectronic infrastructure and fiber optics to make TV and Internet work. It comes down to the individual at work doing their job, even though many of the tools will be similar, the specific details give aid and benefit where needed, and can be largely ignored otherwise. -- Rick C. Hodgin |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Nov 06 05:41PM On 06/11/2018 14:49, Rick C. Hodgin wrote: [snip] > I just happen to know I'm right. And Satan invented fossils, yes? /Flibble -- "You won't burn in hell. But be nice anyway." – Ricky Gervais "I see Atheists are fighting and killing each other again, over who doesn't believe in any God the most. Oh, no..wait.. that never happens." – Ricky Gervais "Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Bryne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?" "I'd say, bone cancer in children? What's that about?" Fry replied. "How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil." "Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say." |
"Rick C. Hodgin" <rick.c.hodgin@gmail.com>: Nov 06 09:51AM -0800 On Tuesday, November 6, 2018 at 12:42:00 PM UTC-5, Mr Flibble wrote: > [snip] > > I just happen to know I'm right. > And Satan invented fossils, yes? No. He invented the lie that says he invented fossils, and then spread that lie around under false pretenses, designed entirely to deceive people who will not seek the truth under any circumstance whatsoever. It breaks my heart, Leigh. If I knew how to reach you in a way which would reach you ... I'd do it. -- Rick C. Hodgin |
jameskuyper@alumni.caltech.edu: Nov 06 10:28AM -0800 On Tuesday, November 6, 2018 at 4:50:07 AM UTC-5, David Brown wrote: ... > saying that the "addressable storage unit" here has to be of the size > and type of the bit-field's type - indeed, "An implementation may > allocate any addressable storage unit large enough to hold a bit-field". The only requirements on the "addressable storage unit" are: "If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low- order or low-order to high-order) is implementation-defined." (6.7.2.1p11). There's no requirement that the size of the unit be documented, nor that it be the same for different struct types. There's certainly no requirement that it be connected to the type used to declare a bit- field. > However, the usefulness of bit-fields for "conforming to externally > imposed layouts" would be hindered if the implementation did not give > the programmer control over the sizes here. Strictly speaking, the requirements that the C standard fails to impose on the layout of structs in particular, and on bit-fields in particular, make C structs useless, in code intended to be portable, for describing externally imposed layouts. I don't approve of this (as shocking as that fact might seem to those who claim that I worship the holy standard). But this state of affairs exists because, at the time the first standard was being written, different compilers implemented different rules for the layout of structures, and no agreement could be reached to mandate stricter requirements than the ones we currently have. That state of affairs continues to the present, and requirements of backwards compatibility makes it difficult to impose any new restrictions in future versions of the standard. The best we could hope for is some new way of defining struct types (or perhaps, something struct-like but using different syntax) that have layouts more tightly constrained by the standard than ordinary struct types. In the mean time, the closest you can get to portable code for externally-imposed memory layouts, is to mask and shift operations on the members of arrays of unsigned char. > Older C compilers sometimes had support for only "signed int" and > "unsigned int" as bit-field types - Those two are the only types that all versions of the standard have mandated support for - since C99 it also mandates support for _Bool as a bit-field's type. Implementations are explicitly allowed to support other integer types, but code that needs to be portable can't take advantage of that fact. > would have used smaller underlying storage units, while I think more > modern ones use the type you ask for. But it is, naturally, > implementation-dependent. It didn't have to be - that's just the way C was defined. |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Nov 06 09:41PM +0100 On 06.11.2018 15:01, Öö Tiib wrote: > | implementation-defined." > Why? Who benefits from such a wasted feature? That could be defined > to follow order of bytes on platform. Well, the g++ implementation of the now deprecated conversion to/from UTF-8 in the standard library. Worth noting that Visual C++ screws up in a different way. So it's perhaps good that it's now deprecated, but AFAIK there's no replacement. :( Cheers!, - Alf |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Nov 06 10:38PM On 06/11/2018 17:51, Rick C. Hodgin wrote: [snip] > No. He invented the lie that says he invented fossils, [snip] Satan doesn't exist mate. And Satan invented fossils, yes? /Flibble -- "You won't burn in hell. But be nice anyway." – Ricky Gervais "I see Atheists are fighting and killing each other again, over who doesn't believe in any God the most. Oh, no..wait.. that never happens." – Ricky Gervais "Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Bryne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?" "I'd say, bone cancer in children? What's that about?" Fry replied. "How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil." "Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say." |
ram@zedat.fu-berlin.de (Stefan Ram): Nov 06 10:23PM >What is the best and most standard way to print objects of your >classes? These actually are two questions: - What is the best /interface/ your class should support to print its object? and - What is the best /implementation/ of this interface? With regard to the interface, it was, IIRC, Herb Sutter wh who suggested something like: class example { ~~~ public: ::std::ostream & print( ::std::ostream & stream )const { ~~~ } ~~~ } inline ::std::ostream& operator << ( ::std::ostream & stream, example const & object ) { return object.print( stream ); } . For the rationales read, IIRC, "class mechanics" by Herb Sutter (preferably an updated version). |
Steve Keller <keller@no.invalid>: Nov 06 06:11PM +0100 What is the best and most standard way to print objects of your classes? In other people's code I often find something like this: class Foo { public: std::string toString() const { std::ostringstream s; s << "{..." << /* more items */ << "}"; return s.str(); }; class MyEnum { enum { A, B, C } e; public: std::string toString() const { switch (e) { case A: return "A"; case B: return "B"; case C: return "C"; } }; void some_other_func(const Foo &f, const MyEnum &e) { std::cout << f.toString() << ' ' << e.toString() << std::endl; } However, I prefer to implement functions that print to std::ostream directly, instead of writing to std::stringstream, then creating a string, and then printing the string to an ostream: class Foo { public: void print(std::ostream &os) const { os << "{..." << /* more items */ << "}"; } }; std::ostream &operator<<(std::ostream &os, const Foo &foo) { foo.print(os); return os; } class MyEnum { enum { A, B, C } e; public: void print(std::ostream &os) const { switch (e) { case A: os << "A"; break; case B: os << "B"; break; case C: os << "C"; break; } }; std::ostream &operator<<(std::ostream &os, const MyEnum &e) { e.print(os); return os; } void some_other_func(const Foo &f, const MyEnum &e) { std::cout << f << ' ' << e << std::endl; } Since I see the first method so often I wonder if there is something wrong with my solution. Does the above approach have any advantages I don't see? Steve |
Paavo Helde <myfirstname@osa.pri.ee>: Nov 06 07:57PM +0200 On 6.11.2018 19:11, Steve Keller wrote: > std::string toString() const { > However, I prefer to implement functions that print to std::ostream > directly, The stream approach is architecturally more sound, more flexible and more customizable. For example, if your object "stringification" involves floating-point numbers then the toString() function has to decide how to format the decimal point: by the current locale, always as '.', etc. When using the stream approach, the client code is assumed to know what it wants and to imbue the needed locale to the stream. At least this is the intention. In practice the customization possibilities provided by locales are often far too few and too little to provide anything better than inconsistencies and grammar errors, so I'm not sure if they do more good than harm. The strings approach typically avoids all this flexibility and customizations. This means the result is always in fixed format and the performance is usually better (string+= won up to 2x in my measurements, compared to ostringstream<<). So the answer depends on your needs and preferences. Is the printout meant for humans or for other software? If for humans, is it for a single person or for many? Is the speed important? Is fixed format important? Etc. |
Jorgen Grahn <grahn+nntp@snipabacken.se>: Nov 06 07:48PM On Tue, 2018-11-06, Steve Keller wrote: > s << "{..." << /* more items */ << "}"; > return s.str(); > }; ... > However, I prefer to implement functions that print to std::ostream > directly, instead of writing to std::stringstream, then creating a > string, and then printing the string to an ostream: ... > Since I see the first method so often I wonder if there is something wrong > with my solution. Does the above approach have any advantages I don't see? I suspect the first approach is a Java/whatever other language influence. To me it means working against the intention of the language (but I don't see it much). /Jorgen -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o . |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Nov 06 09:33PM +0100 On 06.11.2018 18:11, Steve Keller wrote: > s << "{..." << /* more items */ << "}"; > return s.str(); > }; This code suffers from non-systematic indentation. Also, please use spaces, not tabs. The presentation of tabs depends on the software used to view the message, so tabs can really mess up things. From the string format you've chosen it appears that the purpose of "print objects of your classes" is tracing and debugging, not interaction with a user or storing a description from which an equal object can be reconstituted (serialization and de-serialization). For tracing and debugging involving an iostream's locale machinery and general inefficiency, is IMHO counter-productive. One could build on `std::to_string`, but that involves the C locale machinery and forced dynamic allocations for the string buffers. Not quite as bad as the C++ level, but results that depend on a global easily modified state, means unpredictable results in general. Happily, C++17 introduced ¹`to_chars`. Unfortunately, (1) there's apparently no way to predict the required buffer size, except by using `snprintf`, the design or possibly (but not likely) just its documentation, is bungled, and (2) the g++'s standard library implementation libstdc++ ²doesn't yet support `to_chars`. It's not that big a deal to define that kind of functionality, and there are 3rd party libraries that do, but I think I would assume a locale that at worst uses mainland European "," instead of ".", and /under that assumption/ accept the slight performance hit from the C locale stuff (essentially, replacing any produced ",") and just use `snprintf`: ------------------------------------------------------------------------- #include <algorithm> // std::replace #include <iterator> // std::size #include <string> // std::string #include <stddef.h> // ptrdiff_t namespace cppx { template< class A_type > using Type_ = A_type; using Size = ptrdiff_t; template< class Container > auto n_items( const Container& c ) -> Size { return std::size( c ); } } // namespace cppx namespace my { using cppx::n_items, cppx::Type_, cppx::Size; using std::string, std::replace; // Always returns the number of chars that /would/ be generated on success. auto convert_to_text( const double x, const Type_<char*> buffer, const Size buffer_size ) -> Size { const Size n_chars = snprintf( buffer, buffer_size, "%g", x ); if( n_chars <= buffer_size ) { replace( buffer, buffer + n_chars, ',', '.' ); } return n_chars; } auto to_string( const double x, string buffer = string( 16, '\0' ) ) -> string { const Size n_chars = convert_to_text( x, buffer.data(), n_items( buffer ) ); if( n_chars > n_items( buffer ) ) { buffer.resize( n_chars ); convert_to_text( x, buffer.data(), n_items( buffer ) ); } return buffer; } } // namespace my #include <iostream> auto main() -> int { using namespace std; cout << my::to_string( 3.14e15 ) << endl; } ------------------------------------------------------------------------- It shouldn't be difficult to add support for other formats, field width, precision and whatever. > return "C"; > } > }; I guess the intent is to somehow provide client code with three global static instances of `MyEnum`, corresponding to the three `enum` values. Instead of a `switch`, just use an array of values. auto to_string() const -> const char* { static const Type_<const char*> names[] = {"A", "B", C"}; return names[e]; } By the way, using all uppercase for values runs the risk of inadvertent text substitution. In C and C++ you can avoid needless work and needless annoyance by reserving all uppercase identifiers for macros -- and the few idiomatic other uses such as `T` for template parameter type. > However, I prefer to implement functions that print to std::ostream > directly, instead of writing to std::stringstream, then creating a > string, and then printing the string to an ostream: It's unclear what the "instead of" refers to. You haven't illustrated any such code. > foo.print(os); > return os; > } This is the conventional way to do things. It scales, it's reasonably type safe, but it's in practice inefficient /and/ it doesn't handle nationalization well. Better with format strings. Check out e.g. the Boost Format library. > os << "C"; break; > } > }; Again, better use an array than a `switch`. Note that this approach is good only where the client code wants the text output to a stream. For that case it's just about as efficient and clean to use as the `const char*` function I presented above. For any other use it drags in inefficiency and makes the usage unclean. > } > Since I see the first method so often I wonder if there is something wrong > with my solution. Does the above approach have any advantages I don't see? Uhm, don't know. But regarding the "so often", IMO that indicates that you are exposed to code that is not typical. Cheers!, - Alf Notes: ¹ https://en.cppreference.com/w/cpp/utility/to_chars ² https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.2017 |
red floyd <dont.bother@its.invalid>: Nov 06 02:09PM -0800 On 11/6/2018 12:33 PM, Alf P. Steinbach wrote: > On 06.11.2018 18:11, Steve Keller wrote: ------------ > static const Type_<const char*> names[] = {"A", "B", C"}; > return names[e]; > } In this individual case, yes, an array works. But remember, enums do not need to be consecutive, in which case some other mechanism is required. One size does not fit all. |
scott@slp53.sl.home (Scott Lurndal): Nov 06 03:18PM >> in size. >I hadn't actually read that bit of the thread! >CHAR_BIT is /always/ at least 8, so you are safe there. Wasn't always. 6-bit characters were very common (DEC, Burroughs) a few decades ago (e.g. at the time C was developed). |
Manfred <noname@add.invalid>: Nov 06 07:55PM +0100 On 11/6/2018 4:18 PM, Scott Lurndal wrote: >> CHAR_BIT is /always/ at least 8, so you are safe there. > Wasn't always. 6-bit characters were very common (DEC, Burroughs) a few > decades ago (e.g. at the time C was developed). But the ISO standard requires CHAR_BIT to be equal or greater than 8. |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Nov 06 06:24PM On 6 Nov 2018 01:50:02 GMT > | ^~~~~~~~~~~~~ > Does this warning make sense for a /non-member/ function? > Also feel free to suggest any improvements to my code! [snip] This warning seems to be concerned with gcc function attributes rather than the C and C++ keyword 'const'. If so, it signifies that the function does not read any global data and only depends on its arguments: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes It looks as if you have specifically asked for this "warning" (it isn't really a warning) with the -Wsuggest-attribute=const compiler flag. |
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