From: david.brown@hesbynett.no   
      
   On 01/12/2025 15:41, bart wrote:   
   > On 01/12/2025 04:10, Waldek Hebisch wrote:   
   >> bart wrote:   
   >>> On 01/12/2025 00:08, Waldek Hebisch wrote:   
   >>>> bart wrote:   
   >>>>>   
   >>>>> Yet what I said is pretty much true. Nobody care about BitInt until   
   >>>>> they   
   >>>>> became aware of, and now it's must-have.   
   >>>>   
   >>>> Well, you were told many times that regulars here know deficiencies   
   >>>> of C. "Nobody care about BitInt" in the sense that before _BitInt   
   >>>> people will say "this can not be expressed directly in C, you need   
   >>>> such and such workaround". People did not loudly complain   
   >>>> knowing that complaints would achive nothing. But say doing   
   >>>> language comparisons they could note that C lack such a feature.   
   >>>>   
   >>>> There is also a psychological phenomenon: computers even in crude   
   >>>> form are quite useful. So people were willing to jump hops to   
   >>>> use them. But when better/easier approach is available people   
   >>>> wery strongly resist going to old ways. So, once w got _BitInt   
   >>>> you will not be able to take it back.   
   >>>   
   >>>   
   >>> I've been claiming that _BitInt was a poor fit for a language at the   
   >>> level of C which lacks some more fundamental features.   
   >>>   
   >>> But I think I was wrong: the way _BitInt has been devised and presented   
   >>> is actually completely in line with the haphazard way C has evolved up   
   >>> to now.   
   >>>   
   >>> I made the mistake in this thread of thinking that people cared about   
   >>> measured language design; obviously if they're using C, they don't.   
   >>>   
   >>> unsigned char* p;   
   >>> uint8_t* q; // only exists when stdint.h   
   used   
   >>> unsigned _BitInt(8)* r;   
   >>> char* s;   
   >>>   
   >>> p and q are probably compatible. p and r are not; q and r and not. s is   
   >>> incompatible with p, q, r even if it is unsigned.   
   >>   
   >> Do you understand that uint8_t and _BitInt(8) are different types?   
   >   
   > Well, apparently they aren't. It's not immediately obvious why, but as I   
   > explained above, I realise this is entirely in keeping with how C works.   
   >   
      
   C - like many languages - has a variety of types for different purposes,   
   and with different combinations of characteristics. Some separate types   
   share one or more of these characteristics. Characteristics of types   
   include whether they hold integers, floating point values, or pointers,   
   whether they are signed or unsigned, what implicit conversions take   
   place and in what circumstances, what size their bit representation is,   
   what range they cover, what operations can be applied, and so on.   
      
   Just because two types happen to share the same size in bytes does not   
   in any way imply they are, or should be, the same type. Even if they   
   have many characteristics in common, they can still be different types.   
      
   And even when they are /actually/ the same type - such as when one is a   
   typedef of another - it is not difficult to keep them separate in code   
   and use the appropriate type for appropriate use. "size_t" will   
   typically be a typedef for "unsigned long long int", "unsigned long   
   int", or "unsigned int" - but you don't mix it with those types.   
      
   If you had been paying attention in this thread, you /would/ find it   
   immediately obvious why "uint8_t" and "_BitInt(8)" /must/ be different   
   types. And if you had a basic understanding of the way the language   
   works (rather than just a superficial idea of how some of it can be   
   used), you'd understand that these would be different types even if they   
   followed the same integer promotion rules.   
      
   >> And the difference is not an accident, but they have different   
   >> properties (uint8_t in expressions promotes to int, _BitInt(8)   
   >> is not subject to this promotion).   
   >   
   > This is another little rule that is not obvious, and out of keeping with   
   > how other types work. Yet add _BitInt(8) to _BitInt(16), and one side   
   > /is/ promoted.   
   >   
      
   No, _BitInt's never use integer promotion. Perhaps you mean that they   
   are included in the rules for "usual arithmetic conversions" ? These   
   are different from the "integer promotion" rules. One would think that   
   someone who claims to have implemented a C compiler would be familiar   
   with the types of implicit conversions required by the language.   
      
   > My example was just to highlight the plethora of type denotations that   
   > exist, even for the same machine type. The rules for type-compatibility   
   > and promotions (and the ugly syntax) is just icing on top.   
   >   
      
   C is not an abstraction for a processor. It is a programming language.   
   It does not differentiate between types nearly as much as I would like,   
   but it still does so more than an untyped language like assembly.   
      
   > This ungainly way to evolve a language is how C works (just look at all   
   > the things wrong with how stdint.h types were handled).   
   >   
   > The following table for example shows the rules for mixed sign   
   > arithmetic: S means the result (32 or 64 bits) has signed type, and u   
   > means it is unsigned:   
   >   
   > u8 u16 u32 u64 i8 i16 i32 i64   
   >   
   > u8 S S u u S S S S   
   > u16 S S u u S S S S   
   > u32 u u u u u u u S   
   > u64 u u u u u u u u   
   >   
   > i8 S S u u S S S S   
   > i16 S S u u S S S S   
   > i32 S S u u S S S S   
   > i64 S S S u S S S S   
   >   
   > But of course, every C programmer knows this and doesn't need such a chart!   
      
   C programmers know that C does not have types of these names. And I   
   expect most C programmers figure things out using the very simple and   
   consistent rules of the language. Whenever an "int" could be used, if a   
   value of standard integer type is smaller than "int" it gets promoted to   
   "int". Then for any operation that needs two operands of the same type,   
   the smaller type gets converted to the bigger type - and if you mix   
   unsigned and signed, they get converted to unsigned.   
      
   You might not think that these are the best rules to choose for a   
   language (I certainly don't - they were picked for backwards   
   compatibility more than anything else), but they really are not   
   difficult to understand or learn. No one needs a chart.   
      
   >   
   > Here, i8 + u8 gives a signed result; but 'unsigned _BitInt(8 ) +   
   > _Bitint(8)' apparently gives an unsigned result (tested using _Generic).   
   >   
      
   Or you could learn the very simple rules, and then you would know   
   without testing.   
      
      
   [continued in next message]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   
|