GCC ARM32 comparison question - Page 1
Forum section: electronics / general

author: peter-h
author_rank: Super Contributor
timestamp: June 17, 2022, 03:50:27 pm
content: Code:volatile uint8_t a=0xaa;volatile uint8_t b=0x55;volatile bool fred=false;if (a != ~b){fred=true;}// now fred=trueb=~b;fred=false;if (a != b){fred=true;}// now fred=falseHow does this work? Does inverting a byte produce some larger variable? Even this doesn't work:Code:if (a != (~b))

author: Siwastaja
author_rank: Super Contributor
timestamp: June 17, 2022, 04:10:03 pm
content: This is basic C, you can Google it all, or read any tutorial - and of course, the standard itself (any version really). Instead of direct answer, let me help you with keywords:C operators:~ operator!= operatorhttps://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2BC integer promotionBTW, from the strange way of using volatile I'm assuming you are flashing this on an MCU target and looking at it in debugger, am I right? But IMHO, for simple "how does that language work" tests, I would prefer just having gcc installed on your PC, write a small program and use printf(). This easily extents to be a larger unit test where you can loop through possible values and check the correctness.

author: Nominal Animal
author_rank: Super Contributor
timestamp: June 17, 2022, 04:11:39 pm
content: Quote from: peter-h on June 17, 2022, 03:50:27 pmYou forgot the automatic integer promotions C compilers (have to) do. Everything smaller thanintthat can be described by anint, gets converted to anint, and so on.The correct expression here isif (a != (uint8_t)(~b))

author: peter-h
author_rank: Super Contributor
timestamp: June 17, 2022, 04:15:27 pm
content: Yes; embedded target. I really should set up Borland C v3.1 on my PCI did suspect the uint8_t was being converted to an int, so~0becomes0xfffffffffor the comparison (or some such).The reason this has not caught me out before is because most of my 32F417 coding has been uint32_t, flipping bits destined for registers, etc.

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 17, 2022, 05:59:52 pm
content: Yep, integer promotion is the key to integer arithmetics in C. And yep, it can be a bit confusing and a bit annoying. As shown above, you'll need explicit conversions.

author: peter-h
author_rank: Super Contributor
timestamp: June 17, 2022, 07:18:22 pm
content: Why is the cast needed?It is surely obvious what the intention is? Comparing a byte with (say) 32 bits is meaningless, unless one "knows" the int value will always fit within a byte.

author: Nominal Animal
author_rank: Super Contributor
timestamp: June 17, 2022, 07:49:42 pm
content: Quote from: peter-h on June 17, 2022, 07:18:22 pmBecause the C standard says that before an expression is evaluated, integer promotions are performed.We cannot avoid that, but we can fix the comparison logic by casting the promoted value back touint8_trange and precision. (Since C99, a cast suffices – regardless of optimization level – to limit the cast expression to the range and precision of the cast type.)

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 17, 2022, 07:53:42 pm
content: I set the '-Wconversion' flag in compilers to catch potential implicit conversion issues, and I highly recommend it.Unfortunately, it doesn't catch anything in this particular comparison case.As Nominal said, integer promotion is a basic rule in C, and it's just the way it works. It *does* confuse a lot of people.With your example, what seems the most confusing to many is that a unary operator will trigger integer promotion, while you'd usually expect it to preserve the original type of the operand. I do not think that not preserving the original type is a good idea here, but I didn't design C nor was ever part of the std commitee, so my opinion probably doesn't matter much, and doing otherwise in any new std revision would probably break too much code to be even considered.To completely avoid this kind of "issues", you'd need a strongly-typed language, such as Ada, which wouldn't even allow comparing objects of a different type (unless you provided the corresponding operator.)Implicit conversions are, IMHO, the "root of all evil", but in practice, there seems to be way more people hating too strongly-typed languages than people hating implicit conversions (which look convenient at first sight), so... there you have it. Pick your poison.

author: peter-h
author_rank: Super Contributor
timestamp: June 17, 2022, 09:26:15 pm
content: QuoteWhy would that be a good idea?I know cases like sscanf which always read integers and there is no way to get them to read directly into a uint8_t for example.

author: Nominal Animal
author_rank: Super Contributor
timestamp: June 17, 2022, 10:22:57 pm
content: Quote from: peter-h on June 17, 2022, 09:26:15 pmC is an imperfect tool; that's just how it works.

author: newbrain
author_rank: Super Contributor
timestamp: June 17, 2022, 11:20:01 pm
content: Quote from: peter-h on June 17, 2022, 04:15:27 pmI hope you are joking. I fear you aren't.Quote from: peter-h on June 17, 2022, 09:26:15 pmMostly, hysterical raisins.You can read more in an old, but very good document:"Rationale for International Standard — Programming Languages — C"Specifically, in chapter 6.3 Conversions.The whole doc is worth reading though, as a companion to the standard - it was written originally for C89, but was updated to reflect C99.

author: oPossum
author_rank: Super Contributor
timestamp: June 18, 2022, 04:52:20 am
content: Code:if((a^b) == 0xFF) { } // Lower 8 bits are compliment

author: peter-h
author_rank: Super Contributor
timestamp: June 18, 2022, 05:27:51 am
content: QuoteI was jokingBut I still have the manuals on the shelf.I can very easily test C code on my 32F417 target. I have an RTOS task called APP and just stick it in there.I did read that C document on "integer promotion" and still don't get why this is needed. They could just treat uint8_t and int8_t as genuine standalone variable types. Currently, it seems, they get promoted to uint and int respectively for any operations, so their only advantage is less storage space.

author: ataradov
author_rank: Super Contributor
timestamp: June 18, 2022, 05:59:39 am
content: C is old and its promotion rules are generally considered bad. Modern languages handle this much better. And "uint8_t" and "int8_t" were added to the standard decades after the initial release, and the original type system is much less strict and poorly (platform and implementation) defined.Also, if there were no promotion, you will be equally surprised by arithmetic operations. I bet you rely on that a lot in your code.

author: peter-h
author_rank: Super Contributor
timestamp: June 18, 2022, 06:18:39 am
content: QuoteCan you give me an example?Actually I don't do arithmetic on byte variables, other than ++ or --. Also I never use int8_t. On the ARM32 the perf is so high there is no point. I don't use pointers, and use int or uint32_t as an array index. Even float mult is 1 clock. It's a different world.But in the old days people wrote whole programs in byte variables for speed. For example Honeywell did an autopilot (KFC225) which appears to do its algorithms using signed bytes (with occassional severe underflow problems as it happens). On the other hand, and AFAIK they used C, it would not have gained them much because bytes would be promoted to int which on the CPU they used would be a 16 bit reg so unless one uses asm code (e.g. 8x8=16 multiply) you gain little. In those days, 1980-1995, I used only asm, on all the CPUs listed below except arm32.

author: ataradov
author_rank: Super Contributor
timestamp: June 18, 2022, 06:41:28 am
content: I don't know what you man by "in byte variables for speed", but "int" is guaranteed to be faster, since on 16- and 32- bit CPUs compilers have to issue extra instructions to comply with 8-bit semantics. Some people think they are optimizing (like using uint8_t in short "for" loops), but in reality they are just making things worse.As for the example - any reasonably complicated expression with data in byte arrays. For example, you have an array of 5 bytes and you want to calculate average:Code:uint8_t a = {1, 123, 27, 13, 222 };uint8_t avg = (a + a+ a+ a+ a) / 5; // Wrong without promotionuint8_t avg = ((int)a + (int)a+ (int)a+ (int)a+ (int)a) / 5; // You would have to do something like this.Depending on the new rules, only the first manual promotion may be necessary, but that is error-prone when making modifications.Stuff like this happens all the time.And again, C promotion rules are not good, but it is what it is, and if you want to use C, you just need to learn them.

author: peter-h
author_rank: Super Contributor
timestamp: June 18, 2022, 08:04:51 am
content: QuoteI am sure you know all this, so I am surprised by your question.Take the Z80. HL holds a uint16_t x and you are doing x << 4.ld b, 4loop: add hl, hldjnz loopThe loop counter is a byte.If you were forced to an "int", which on an IAR C compiler was 16 bits, you would need something likeld bc, 4loop: add hl, hldec bcld a, bor cjr nz, loopThere is a million cases where 8 bit values is far faster, on those micros. One also had 8x8=16 multiply, 16/8=8 divide, etc. Converting every int8 into 16 bit arithmetic bloats the code 5x to 10x. In fact I remember rewriting a lot of IAR code in asm and wondering why they are doing everything in 16 bits, with the top byte set to 0. 8x8=16 is probably 10x faster than 16x16=32 and then discarding the top 16 bits. No wonder C got a crap name back then for generating crap codeIn later years, CPUs became "genuinely 16 bit" even though they still had the crippling 64k address space. H8/500 was one such.On the arm32 I use int or uint32_t for loop counters; it merely wastes RAMRe your example, that is wrong codebecause anybody adding up even two bytes should know the result can be > 255. Classic integer maths overflow. If using integers (rather than floats) one needs to be intimately familiar with theactualrange of values i.e. the actual data. This was well known since for ever. The Apollo guidance stuff used int32 heavily and had to deal with this. So avg should be a uint16_t and possibly a uint32_t if adding up lots of them. Auto promoting avg to uint16_t only saves your skin partially, and hides the real problem.People who can't be bothered with actual data ranges have to use floats - and pay a heavy price it... in the old days, of x100 to x1000 less speed. Not today, with a 168 megaflop 32F417.AIUI,uint32_tavg = (a + a+ a+ a+ a) would promote each of the five items to a uint32_t before doing the addition. That's probably wrong too

author: brucehoult
author_rank: Super Contributor
timestamp: June 18, 2022, 08:09:37 am
content: Quote from: peter-h on June 18, 2022, 06:18:39 amBoth of those pessimise speed on different machines. The best choice if you're indexing from the actual name of the array is size_t. If you're indexing from a pointer that may be into the middle of an array then ptrdiff_t is better than int.

author: brucehoult
author_rank: Super Contributor
timestamp: June 18, 2022, 08:30:51 am
content: Quote from: peter-h on June 18, 2022, 08:04:51 amThat's kind of dumb because it's no bigger, and much faster, to do as sdcc does:Code:#include <stdint.h>uint16_t shl4(uint16_t n){return n<<4;}Using "sdcc -mz80 --opt-code-size -S dumb_loop.c":Code:.area _CODE;dumb_loop.c:3: uint16_t shl4(uint16_t n){;---------------------------------; Function shl4; ---------------------------------_shl4::;dumb_loop.c:4: return n<<4;addhl, hladdhl, hladdhl, hladdhl, hlexde, hl;dumb_loop.c:5: }retOk, let's make it a variable shift:Code:uint16_t shl4(uint16_t n, int sh){return n<<sh;}Code:.area _CODE;dumb_loop.c:3: uint16_t shl4(uint16_t n, int sh){;---------------------------------; Function shl4; ---------------------------------_shl4::;dumb_loop.c:4: return n<<sh;ldb, eincbjr00104$00103$:addhl, hl00104$:djnz00103$exde, hl;dumb_loop.c:5: }retHmm. I guess you forgot that any shift amount over 16 is going to give the same result -- 0 -- so you don't have to worry about counts over 255. But the compiler didn't forget!

author: newbrain
author_rank: Super Contributor
timestamp: June 18, 2022, 08:48:45 am
content: Quote from: peter-h on June 18, 2022, 08:04:51 amThe result of the expression that is the right operand of the '=' operator will be converted to uint32_t.But the operands of the four '+' operators sub-expressions will be converted to signed int, as discussed above.The final effect is the same, in this specific case.Quote from: peter-h on June 18, 2022, 06:18:39 amLiar, liar, pants on fire.

author: Siwastaja
author_rank: Super Contributor
timestamp: June 18, 2022, 10:30:42 am
content: Quote from: SiliconWizard on June 17, 2022, 07:53:42 pmI totally agree, yet most people seem to have gripes with C beingtoo strongly typed, i.e., they want even weaker typing, to the point of automatic implicit conversions from anything to anything, with little or no control over types at all. It seems easy on surface, but such lack of control is a recipe for disaster. C is at least halfway there to strong typing.

author: peter-h
author_rank: Super Contributor
timestamp: June 18, 2022, 10:35:26 am
content: This has been a huge learning experience for me.So, AIUI, C makes any variable size shorter than int pointless, unless you are trying to save storage space.In particular (unless very short of stack space) using a variable smaller than int inside a function is pointless because any storage used is chucked away upon exit. And a lot of variables are optimised anyway so never stored in RAM.This is why I have not been bitten by this (until yesterday) because the bulk of my C programming has been on the arm32 and there I know the arm32 is natively 32 bit so uint8_t int8_t uint16_t int16_t are pointless. The only time I have used int16 was for peripherals registers which are 16 bit, like DMA transfer counters. uint8_t I have used for buffers, obviously, because practically all "data" is byte sized. My previous C coding was a little bit of hacking somebody else's C code about 20 years previously.I still wonder why C doesn't internally represent bytes as bytes. They are quite common in embedded systemsExpanding every byte retrieved from a buffer to 32 bits doesn't generate more code, or lose speed, on an arm32, but on most older stuff it does one or the other or both. Of course few people care about old CPUs today...I do know djnz, btw - I posted it aboveStrong typing is a PITA. I did tons of Pascal and even implemented a Pascal compiler on an embedded customer-programmable product. The language was near-useless without a lot of extensions.

author: Siwastaja
author_rank: Super Contributor
timestamp: June 18, 2022, 10:41:26 am
content: Quote from: peter-h on June 18, 2022, 05:27:51 amYou are missing the fact that a language which actually runs and enables a big part of our computerized world, the language needs to be properly standardized and specified. Compilers just can't work they way which would seem logical or good, because then everyone would disagree about what it exactly is.In the process of standardization, poor choices happen, it is inevitable; people make mistakes, have bad ideas, or are thinking about some different use case which ends up being irrelevant.C is a product of such process, it's far from perfect.C's strengths are:* Itisstandardized, proper language, which changes slowly. It's stable.* It is good enough,* While it has a dozen of stupid ideas or footguns, it doesn't have hundreds of them. A normal human being with say 110IQ, with programmer mentality, can actually learn the language in a few years!Languages that fundamentally change all the time, or specification is all over the place, become toy languages like Python or PHP. They are usable in their own domain, of course. But there is a difference: if you ask why something is brain-dead in C or in PHP, for C, the reason is: "it was considered a good idea in 1980's. it is standardized like this, all greybeards know it, and it has to stay that way for compatibility". For PHP, the answer is: "no one knows. It's just a bug. It may or may not randomly change."

author: brucehoult
author_rank: Super Contributor
timestamp: June 18, 2022, 11:09:43 am
content: Quote from: peter-h on June 18, 2022, 10:35:26 amNo, not at all.The C language always specifies things "as if". Integer calculations on values shorter than int must act "as if" they were promoted to int and the calculation done in int. But if the ISA in question has the ability to do operations directly on bytes or shorts AND the compiler can prove that the result will be the same, then it is allowed to use them.Code:char addb(char *b, char *c){return *b + *c;}Z80 (using sdcc):Code:_addb::ldc, (hl)lda, (de)adda, cretx86_64: (gcc)Code:addb(char*, char*):movzx eax, BYTE PTR add al, BYTE PTR retMSP430:Code:addb(char*, char*):MOV.B @R12, R12ADD.B @R13, R12RETx86: (msvc)Code:char addb(char *,char *) PROC ; addb, COMDATmov eax, DWORD PTR _b$[esp-4]mov ecx, DWORD PTR _c$[esp-4]mov al, BYTE PTR add al, BYTE PTR ret 0All of those are compiling C code to use byte ALU operations.It's not at all pointless to use char and short.If the result of the function was int instead of char then the code would be different, with a full 16 bit (or more) add -- or at least with the next byte getting the carry flag (if char is unsigned).

author: peter-h
author_rank: Super Contributor
timestamp: June 18, 2022, 11:29:59 am
content: OK, sure, but nobody answered my questionExcept in terms of "it is the C standard, so accept it".ISTM that this "promotion to int of almost everything shorter" is an attempt to prevent bad coding leading to what has since for ever been known in the embedded world (whether manually blowing fusible link PROMs one byte at a time, or asm, or C or whatever) as "integer overflow". The cost of doing this is- on CPUs which are mostly not natively int sized (most of the 8/16 bit stuff like the Z80 etc) it bloats a lot of stuff, and slows it down, a lot- if there is enough oveflow to make MSB=1 then you will likely get real problems with any comparisons, because the promotion is tosignedint- it conceals most integer overflow, which is nearly always loss of real data - unless doing a checksum

author: brucehoult
author_rank: Super Contributor
timestamp: June 18, 2022, 11:45:26 am
content: Quote from: peter-h on June 18, 2022, 11:29:59 amWhen the rubber meets the road, yes, that's the specification of the language.As to why...QuoteNo. It's not to protect against sloppy programmers. It's because very many of the machines that C runs on -- basically all mainframes or RISC that started life as 32 bit -- there are only instructions for full register arithmetic, so if you forced them to mask results down to 8 bits after every operation it would be very inefficient.At the same time, machines that *do* have byte arithmetic are -- as I showed above -- free to use it IF IT WILL GET THE SAME RESULT.It's a very pragmatic policy.QuoteRubbish.What does it bloat? You showed one calculation that you said would be bloated on z80 if done in C. I showed actual C compiler output for the z80 which was not bloated.I presented another calculation, and showed that it also was not boated on any of a range of machines.Want to come up with an example which will actually show bloat?QuoteThe MSB of what? A 1 byte value? Promotion of an unsigned char is to (signed) int values from 0-255, and promotion of a signed char is to int values from -128 to 127. Arithmetic and comparisons operated perfectly in either case.If anything, it is *easier* to detect overflow.Examples in C, please.

author: Nominal Animal
author_rank: Super Contributor
timestamp: June 18, 2022, 12:08:14 pm
content: Quote from: peter-h on June 18, 2022, 11:29:59 amWell, itisone of those choices by language developers that have complicated (and often not that convincing) reasoning and history behind it, and cannot be changed without making the result a different programming language.You are probably right in that the reasoning did not emphasize use cases (i.e., us developers and programmers using the language), and instead had more to do with the compiler implementation and the abstract machine approach the C standard uses. There are related things like argument promotion (similar; butfloatis also promoted todouble) applied when there is no prototype or the arguments are passed as variable arguments to a variadic function, see<stdarg.h>) making variadic function calls much easier to support in C, as each passed argument always takes a full native register or native-size word on the stack, depending on the ABI.Just like many others here, I've done paid work in something like a dozen different programming languages. It is useful to wonder why language designers made a specific choice, because itcanreveal their intent and viewpoint (related to the paradigm underlying the language design). However, sometimes such choices don't have any deeper meaning for us developers, because their reasoning is elsewhere, or just plain wrong. I could be wrong, but I've alwaysassumedinteger promotions in C belong to this latter category. It is sometimes useful, sometimes annoying; just something one has to deal with when writing C, without any huge programming paradigm insights in it. Similar to e.g. how you can swap array names and indices in C,abeing equivalent tob. Other than obfuscated code contests, I've never seen a real world use case where that would be actually useful.Quote from: peter-h on June 18, 2022, 10:35:26 amNo; this is exactly why theint_fastN_tanduint_fastN_ttypes were introduced (and standardized in C99 in<stdint.h>), forN= 8, 16, 32, and 64. They provideat least N-bit range, but their actual size depends on what is fast on a particular architecture.For example, on 32- and 64-bit architectures,uint_fast16_tis usually 32 or 64 bit unsigned integer, whichever is "faster" for that architecture.Quote from: peter-h on June 18, 2022, 11:29:59 amActually, it does: it just calls themchar(implementation-defined signedness),unsigned char, andsigned char. In particular,sizeof (char) = sizeof (unsigned char) = sizeof (signed char) = 1by definition –– and the size is not explicitly 8 bits. There are even specific rules about conversion to and from ((un)signed) char buffers in C.It is only in (arithmetic and logical) expressions that integer promotions are done; and also when calling functions without prototypes or variadic functions.So, it is not really about internal representation, and more about the definition of how arithmetic and logical expressions are evaluated.And even then, the compiler does not need to do that, as long as it is proven that the results are the same as if it had done so. (Kinda annoying, yeah, but the C language is defined in terms of an abstract machine.)

author: peter-h
author_rank: Super Contributor
timestamp: June 18, 2022, 12:23:33 pm
content: Thank you. It does clarify it for me, and importantly I can see why my code is working fine, until yesterdayQuoteI can't because I don't have a Z80 C environment and don't have the time to set one up. I probably have the 1980s IAR Z180 compiler somewhere (I don't think it was dongled, but it was ~£1000) and could try with that, but clearly compilers have got a lot more clever since then. I spent months on a particular project coding a lot of its functions in asm. Including runtimes, which were almost certainly written wholly in C too (as distinct from Hitech C which had e.g. printf() in C but a lot of runtime stuff done in asm; Clyde Smith-Stubbs knew his stuff).

author: brucehoult
author_rank: Super Contributor
timestamp: June 18, 2022, 12:36:14 pm
content: Quote from: peter-h on June 18, 2022, 12:23:33 pmI only need source code, I have a z80 compiler. It also does 6502, z180, mcs51, r2k, pic14, pic16, hc08, s08, stm8.QuoteProbably. Certainly the open source ones have. And this isn't even gcc or llvm, because they don't handle the weirdness of 8 bit ISAs very well, but a compiler with a lot less work in it.

author: peter-h
author_rank: Super Contributor
timestamp: June 18, 2022, 12:46:14 pm
content: QuoteYes; a current one.I did another project using an H8/323 in 1997. We used the Hitech C compiler then, which was about £350. That worked well. There was also an open source compiler around (GNU?) which Hitachi were giving away on a CD but it produced hugely bloated code; about 2x bigger than the Hitech one.Further back I used some Zilog-distributed MUFOM tools. Mainly their z280 assembler (I was the first Z280 design-in in Europe, according to Zilog) but there was also a C compiler which was so bloated nobody dared use it for anything real. And a Z8000 compiler, similarly bloated. Reportedly those compilers were generated with YACC.This discussion applies to current tools, and I accept that.

author: dietert1
author_rank: Super Contributor
timestamp: June 18, 2022, 01:02:50 pm
content: Some days ago i made a quick test for a STM32L476 board using IAR IDE. There were some float variables and it used them as intended, except the link map contained lots of double support functions. I found that for invocation of printf all float values got extended to doubles. Probably caused by some project default setting like MISRA or the like.Regards, Dieter

author: Nominal Animal
author_rank: Super Contributor
timestamp: June 18, 2022, 01:19:34 pm
content: Quote from: dietert1 on June 18, 2022, 01:02:50 pmIt's the argument promotion rules I mentioned above that causes that; printf() being a variadic function.See if there is a flag to disableprintf()floatsupport altogether, and if the C library used in IAR IDE supportsstrfromf()(standard C since C99). Sincestrfromf()is not a variadic function,floats are passed without promoting them todouble. It is not as powerful as printf(), because the format string must begin with a%, followed by optional size and/or precision, followed by one of the conversion specifiers valid forfloats (AaEeFfGg).The idea is that you use a small buffer on stack to convert the float to a string first, saychar tempbuf;if (strfromf(tempbuf, sizeof tempbuf, "%.3f",floatvar) >= (int)sizeof tempbuf) {/* Oops, tempbuf[] was not large enough! */} else {/* Print tempbuf as a string */}It's not optimal for sure; just a workaround.When using GCC, the-Wdouble-promotionparameter can be very useful: whenever the compiler decides to do this, this warning flag causes the compiler to emit a warning.

author: brucehoult
author_rank: Super Contributor
timestamp: June 18, 2022, 01:31:14 pm
content: Quote from: peter-h on June 18, 2022, 12:46:14 pmNaturally.QuoteI used all kinds of awful compilers 40 years ago too. And companies thought they could charge a fortune for rubbish.My first C programming was on a Z8000 machine running Unix, as it happens, in 1983 if I recall correctly. Prior to that any high level language programming I'd done on a microcomputer was in either an interpreter or a compiler to bytecode and then interpret that, so anything that compiled to native code was a huge speed improvement.QuoteMore to the point, it applies to what the C language permits or doesn't permit, not to the quality of any particular compiler, though I'm certainly prepared to take compilers producing reasonable code as existence proofs that C doesn't mandate bad code, even on such crude machines as a z80 or 6502.

author: ataradov
author_rank: Super Contributor
timestamp: June 18, 2022, 04:43:30 pm
content: Quote from: peter-h on June 18, 2022, 08:04:51 amI very explicitly said that it is guaranteed to be faster on 16- and 32- bit CPUs. Z80 is not one of them.Quote from: peter-h on June 18, 2022, 08:04:51 amIt is just an example. Believe me, you will be bitten by the lack of promotion and you would create similar topic if they were not there.How to implement promotions is not a simple topic, and in the end you just need to decide something. For concrete examples, you can look at how it is handled in more modern languages like Rust, Go, Swift. They all made their own slightly different decisions.

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 18, 2022, 05:58:43 pm
content: Have you read the rationale document posted by newbrain?

author: ataradov
author_rank: Super Contributor
timestamp: June 18, 2022, 06:07:18 pm
content: Quote from: SiliconWizard on June 18, 2022, 05:58:43 pmIs this for me? If so, yes, I've read this many years ago.From my point of view, the best way to approach promotions is to allow only non-losing widening promotions. There is a good discussion on that herehttps://internals.rust-lang.org/t/implicit-widening-polymorphic-indexing-and-similar-ideas/1141Prohibiting everything results in a lot of pointless castings and doing what C did results in a lot of confusion.

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 18, 2022, 06:11:40 pm
content: Quote from: ataradov on June 18, 2022, 06:07:18 pmNo, sorry for not quoting the OP. That was for the OP.And I'm again not saying that their decision was the right one, but at least we more or less know why C is defined this way.

author: Siwastaja
author_rank: Super Contributor
timestamp: June 18, 2022, 07:21:01 pm
content: Quote from: peter-h on June 18, 2022, 11:29:59 amOf course not! You still don't get it. C isnota "portable assembler". C is a high level language, with the concept of abstract C machine. Compiler is totally allowed to produce optimum code. Compiler only has to prove the result is correct, according to the standard. The problem is you thinking "optimization" as some separate step, as if programmer writes "portable assembler" first, then compiler translates it 1:1 to bloated code, and then optimizer trying to do something about it. It's not like this. Really, programmer gives high-level description of program, using standard language called C. Then compiler produces machine code, the only requirement being it must produce exactly the correct result. It does not matter how the compiler achieves this. Of course compilers try to do this in optimum way.

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 18, 2022, 07:33:25 pm
content: Compilers build an abstract description of the source code before translating that to assembly.Only in the very old and simple compilers both steps were more or less combined (like say, with the original Turbo Pascal compiler.)

author: nctnico
author_rank: Super Contributor
timestamp: June 24, 2022, 12:29:10 am
content: Quote from: peter-h on June 18, 2022, 11:29:59 amThe designers of the C language already thought of that: the size of an int (integer) isn't fixed in C! On 16 bits CPUs an int is typically 16 bit. On 64 bit platforms an int usually is 32 bit.