should this compile ? - Page 1
Forum section: electronics / general

author: snarkysparky
author_rank: Frequent Contributor
timestamp: December 27, 2019, 02:52:30 pm
content: seems like this should not be allowed to compile...Code:void event_sti_set(enum event_sti_number num, unsigned long *eventp){eventp|= event_conv_table.events;eventp|= event_conv_table.events;}I think this would compile but the intention would be clearer.Code:*(eventp + 0) |= event_conv_table.events;*(eventp + 1) |= event_conv_table.events;What do you "c" experts think??

author: SiliconWizard
author_rank: Super Contributor
timestamp: December 27, 2019, 02:59:51 pm
content: This is exactly the same, and both are conforming C. The a operator has the exact same meaning as *(a + k). Guaranteed.

author: ralphrmartin
author_rank: Frequent Contributor
timestamp: December 27, 2019, 05:02:10 pm
content: Quote from: SiliconWizard on December 27, 2019, 02:59:51 pmAnd a serious design flaw, in my opinion. Any intelligent student who "knows" that CPUs address memory in bytes does the intelligent thing, and if they have a array of 32 bit integers (say), "knows" that the next such integer in the array is 4 bytes further along so writes *(a + 4) instead of *(a+1) for the next integer. It's always the smart students who do this. Both the language designer and the student try to fix the same issue, so it gets fixed twice.

author: GromBeestje
author_rank: Frequent Contributor
timestamp: December 27, 2019, 05:28:05 pm
content: They are equivalent. I don't think the intention would be clearer in one syntax or the other. I'd say it's a matter of personal preference.

author: sokoloff
author_rank: Super Contributor
timestamp: December 27, 2019, 05:34:51 pm
content: Quote from: snarkysparky on December 27, 2019, 02:52:30 pmWhat makes you think it shouldn't compile? I think that form is clearer and more idiomatic C than the second form.Now, what would really bend your noodle (and I don't recommend) is this would also work:Code:void event_sti_set(enum event_sti_number num, unsigned long *eventp){0|= event_conv_table.events;1|= event_conv_table.events;}because as SiliconWizard and blueskull mention, a === *(a+c), and addition is commutative.

author: brucehoult
author_rank: Super Contributor
timestamp: December 27, 2019, 05:37:00 pm
content: Quote from: blueskull on December 27, 2019, 03:12:35 pmWhat is not so well known is thateventp == *(eventp+1) == *(1+eventp) == 1

author: SiliconWizard
author_rank: Super Contributor
timestamp: December 27, 2019, 07:07:23 pm
content: Quote from: ralphrmartin on December 27, 2019, 05:02:10 pmNo, CPUs do not necessarily "address memory in bytes" (although it's pretty common, some may not). Second, pointers ARE NOT addresses. I know some see C as very low level, but it's not that low level.This has nothing to do with being intelligent.Pointer arithmetics is well defined in the standard. Just learn, or avoid it altogether (which some safety-critical rules do.)

author: sokoloff
author_rank: Super Contributor
timestamp: December 27, 2019, 07:42:37 pm
content: Quote from: SiliconWizard on December 27, 2019, 07:07:23 pmIn practice, pointers are addresses.

author: DBecker
author_rank: Frequent Contributor
timestamp: December 27, 2019, 08:19:46 pm
content: Quote from: sokoloff on December 27, 2019, 07:42:37 pmPerhaps better worded as "C language pointers are usually implemented as addresses".Other implementations are possible.C was developed in an era where byte-addressed processors were common, but in the minority. Word-addressed machines saved a few bits, back when that was an edge that needed for commercial success. A C 'char' pointer would commonly have a different implementation than a word-data-type pointer.

author: GromBeestje
author_rank: Frequent Contributor
timestamp: December 27, 2019, 08:43:54 pm
content: Quote from: DBecker on December 27, 2019, 08:19:46 pmAnd a byte is not necessary 8 bits in length, even though that's been the standard for many decades.

author: mikerj
author_rank: Super Contributor
timestamp: December 27, 2019, 11:57:40 pm
content: Quote from: ralphrmartin on December 27, 2019, 05:02:10 pmNot smart enough to read a book on the C language apparently.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: December 28, 2019, 12:09:18 am
content: Quote from: GromBeestje on December 27, 2019, 08:43:54 pmInteresting to note that C refuses to standardize some operations (leaving them "implementation dependent" instead), because 1s-complement machines are still covered. Under/overflow and shift, for example.Though I forget if non-8-bit-byte or word machines share a similar historical mandate.Tim

author: SiliconWizard
author_rank: Super Contributor
timestamp: December 28, 2019, 12:22:54 am
content: Quote from: T3sl4co1l on December 28, 2019, 12:09:18 amI think you mean operations on signed integers (OK probably obvious from the "1s-complement", but just to make things clear). Overflow is fully defined with unsigned integers, and just rolls over (which is basically OP (mod 2^N) ).The situation with signed integers is pretty annoying. Of course what it means is that if you want to write portable code, never make your signed integers "overflow".I've seen a lot of code making assumptions about this (which happened to work with come compiler on some machine), and that can break beautifully on some other platform...Quote from: T3sl4co1l on December 28, 2019, 12:09:18 amYep. Quoting the standard, byte is defined like so:Quoteand:QuoteThe standard associates bytes and "characters", so this completely depends on the underlying "execution environment".We had to wait until C99 to get fixed-size integers.Note that this definition of integers as "large enough to hold at least xxx" is not specific to C. The same thing happens with many other "high-level" languages. Interestingly, Pascal and some derivatives cared to define a BYTE (8-bit) type outside of the "CHAR", whereas the typical INTEGER (and I think CHAR) would be treated as in C (with no fixed defined size).

author: cv007
author_rank: Frequent Contributor
timestamp: December 28, 2019, 12:55:04 am
content: >I think this would compile but the intention would be clearer.Many times the array version is clearer, so use when needed as there is nothing wrong in doing so.int main(int argc, char* argv[]){ // -v = verboseif( argc > 1 && argv == '-' && argv == 'v' ) printf("Hello world, how ya doing\n");else printf("hi\n");}int main(int argc, char* argv[]){if( argc > 1 && **(argv+1) == '-' && *(*(argv+1)+1) == 'v' ) printf("Hello world, how ya doing\n");else printf("hi\n");}https://godbolt.org/z/GoJFVHI would say the array access is easier to understand. In many cases that is so.Once you figure out what is 'the same as', then you have choices and there is usually a better one among them but at least you can choose which one makes the most sense at the point of use. Also note when doing addition or array access on these things, the addition/offset is using the size of the underlying type which can get you in trouble when you start doing math on these numbers.

author: jonroger
author_rank: Regular Contributor
timestamp: December 28, 2019, 01:05:36 am
content: Code:void event_sti_set(enum event_sti_number num, unsigned long *eventp){eventp|= event_conv_table.events;I agree that consistency is clearer. For the above, use "unsigned long eventp[]" as the parameter.

author: andersm
author_rank: Super Contributor
timestamp: December 28, 2019, 01:56:10 am
content: Quote from: T3sl4co1l on December 28, 2019, 12:09:18 amC++20mandates two's complement, and finally specifies that right-shifts are sign-extending (signed overflow remains undefined behaviour). It looks likely that these changeswill be adoptedby the next C standard as well.

author: SiliconWizard
author_rank: Super Contributor
timestamp: December 28, 2019, 02:46:14 am
content: Quote from: andersm on December 28, 2019, 01:56:10 amYeah, that makes sense for the right shift, not just because it's expected by most, but also because it makes it more consistent with the '/' operator (meaning that with signed integers and this rule, n >> m would be equivalent to n / 2^m)...

author: westfw
author_rank: Super Contributor
timestamp: December 28, 2019, 06:21:33 am
content: QuoteCPUs that don't address memory in bytes are a bit hellish to write C compilers for, or use C once you do.Especially, if you want to run "standard" C applications.

author: GromBeestje
author_rank: Frequent Contributor
timestamp: December 28, 2019, 09:25:11 am
content: Think about the x86 Real Mode memory model

author: DBecker
author_rank: Frequent Contributor
timestamp: December 29, 2019, 12:44:50 am
content: Quote from: andersm on December 28, 2019, 01:56:10 amMy opinion: it might be about the right time to do this. Perhaps. A decade ago would have been "too soon". I'm not sure that anyone is going to see a performance gain from the change, and incompatibility has a cost.C struck a very useful balance between high- and low-level languages. It could be run on most extant architectures when it was developed, even those that today we consider very odd. And it did so in a way that that barely had an impact on writing for what later became the canonical architecture... VAX.Pretty much the only aspect of common instruction sets that C made inaccessible by supporting a more abstract number encoding model was the ability to effectively access the carry status bit.

author: westfw
author_rank: Super Contributor
timestamp: December 29, 2019, 02:49:29 am
content: QuoteWell, yes, exactly. "Near" and "far" pointers, and multiple "models" for compilation. Functions to "normalize" pointers so that you could tell that 100:0 and 0:1000 were "equal" (did I get that right? It's been a long time.) And yet, still "byte addressable" in most ways; nothing nearly so bad as a DEC-10 that would normally store strings as 5 7-bit bytes in an (addressable) 36bit word.