Live data from Hacker News

To become a good C programmer (2011)

fabiensanglard.net

121–130 of 135 posts

Re: To become a good C programmer (2011)

#121
post #30

Earlier quoted context omitted.

The names in stdint.h are ok, but the way they play with library functions like printf() and scanf() is not so great. Given an int64_t value x, each of these works on some platforms and is wrong on another: printf("here's your int64_t: %ld\n", x); printf("here's your int64_t: %lld\n", x); And the portable way using inttypes.h is really ugly: printf("portably int64_t: %" PRId64 "\n", x); There's another religious argu…

Then there’s the perennial problem of missing format specifiers for POSIX types like pid_t. Although you could argue that POSIX should mandate macros to appropriately handle them, the root problem is the same. The default integer types have not aged well...

The concept of int hasn't aged very well. People think it's fine because it's always 32 bits on their machine. Go recompile on a machine where it's 16 bits and see how that works out.

Re: To become a good C programmer (2011)

#122
post #5

This is a great list of books - at least, I found the same ones were the most excellent. Also I really learnt a lot from 21st Century C (The author here said they wanted to stick to C89, which is fair enough.) >To read great C code will help tremendously. But then he just gives examples of games I don't know and am not really interested in. Anyone know some non-game C that is, I suppose, well-known and wonderfully-wr…

I find the source code of the Netsurf browser really beautiful: - https://netsurf-browser.org/ - https://source.netsurf-browser.org/netsurf.git/tree/ Including the sub projects, for instance: - https://source.netsurf-browser.org/libcss.git/tree/ - https://source.netsurf-browser.org/libdom.git/tree/ It feels immediately obvious and understandable, which is quite impressive for a browser. Everything is well documented,…

Very well written code indeed. Thanks for the links. They could make error management less bug prone by using goto, but it's definitely high quality C code nonetheless.

Re: To become a good C programmer (2011)

#123

Earlier quoted context omitted.

> Go is probably never going to run on microcontrollers due to its very big overhead. My employer runs go on micro controllers. Definitely suboptimal, but as long as the cost of increasing hardware capacity to accommodate Go is feasible then it's a viable option.

Isn't it counter productive to go out of your way to find better hardware to fit your language choice? Why not choose a lighter language?

Libraries might be easier to use, and you can use the same language on the server and hardware.

Re: To become a good C programmer (2011)

#124

Earlier quoted context omitted.

>see how powerful and versatile GPUs have become because they didn't carry that legacy. GPUs are the best example for why C is a good lower-level high-level language, seeing how CUDA is programmed in C/C++. Do you have any examples of architectures that could exist if only they weren't constrained by legacy C?

> GPUs are the best example for why C is a good lower-level high-level language, seeing how CUDA is programmed in C/C++. CUDA is not C or C++. That you can program GPUs in a C/C++-like language does not entail that C/C++ is a natural form of expression for that architecture. > Do you have any examples of architectures that could exist if only they weren't constrained by legacy C? Turing tarpit means that every archit…

>That you can program GPUs in a C/C++-like language does not entail that C/C++ is a natural form of expression for that architecture.

It's not a matter of what is/isn't a "natural form of expression." The point of C/C++ is to be high-level enough for humans to build their own abstractions over hardware. (sounds like an OS, right?) The success of the design of C/C++ is in that the creators had no knowledge of modern GPUs, yet GPUs can efficiently execute them with a little care from developers. We use other abstractions (e.g. SciPy on Tensorflow) because they are more appropriate to solve our problems, but they are built on C.

>Lisp machines and tagged hardware architectures do make such a distinction though, and so more naturally fit. With such distinctions, you could even have a hardware GC.

And why would that not be backwards-compatible with legacy C?

Particularly, I am rejecting the idea that C is somehow stunting hardware development - I see no evidence of this fact. I am also skeptical about the claim (although I will not reject it outright) that there is a language substantially better fit compared to C for low-level programming (e.g. embedded, kernel).

Re: To become a good C programmer (2011)

#125

Earlier quoted context omitted.

What I wonder is, why didn't they add new *printf functions? So you could say 'printf("int64: %d64", x)'

Backward compatibility. Your example would impose additional constraints on the %d specifier that would likely break existing code. What if you want an int immediately followed by literal ”64”?

Oops, I typoed. I said 'new *printf functions'; the example was supposed to be 'printf2("int64: %d64", x)'

Re: To become a good C programmer (2011)

#126
post #105
post #22

Earlier quoted context omitted.

> And there are many websites that cover obscure topics not found in books. Yup. Are there any books covering the same content that ctyme does? ( http://www.ctyme.com/intr/int.htm )

Ah, the famous “Ralph Brown’s Interrupt List”. It was actually published as a book: https://www.amazon.com/PC-Interrupts-Programmers-Reference-T...

just curious. this is not relevant nowadays right?

Re: To become a good C programmer (2011)

#127

Earlier quoted context omitted.

> GPUs are the best example for why C is a good lower-level high-level language, seeing how CUDA is programmed in C/C++. CUDA is not C or C++. That you can program GPUs in a C/C++-like language does not entail that C/C++ is a natural form of expression for that architecture. > Do you have any examples of architectures that could exist if only they weren't constrained by legacy C? Turing tarpit means that every archit…

>That you can program GPUs in a C/C++-like language does not entail that C/C++ is a natural form of expression for that architecture. It's not a matter of what is/isn't a "natural form of expression." The point of C/C++ is to be high-level enough for humans to build their own abstractions over hardware. (sounds like an OS, right?) The success of the design of C/C++ is in that the creators had no knowledge of modern G…

> It's not a matter of what is/isn't a "natural form of expression." The point of C/C++ is to be high-level enough for humans to build their own abstractions over hardware.

Sure it matters. If primitives don't map naturally to the hardware, then you have to build a runtime to emulate those primitives, just like GC'd languages do.

> The success of the design of C/C++ is in that the creators had no knowledge of modern GPUs, yet GPUs can efficiently execute them with a little care from developers

You cannot run any arbitrary C program on a GPU. This fact is exactly why GPUs were able to innovate without legacy compatibility holding them back.

Only later were GPUs generalised to support more sophisticated programs, which then permitted a subset of C to execute efficiently.

The progress of GPUs proves exactly the opposite point that you are claiming. If C were so perfectly suited to any sort of hardware, then GPUs would have been able to run C programs right from the beginning, which is not true.

> And why would that not be backwards-compatible with legacy C?

That's not the point I'm making. Turing equivalence ensures that compatibility can be assured no matter what.

The actual point is that CPU innovations were tested against C benchmark suites to check whether innovations effectively improved performance, and some or many of those that failed to show meaningful improvements were discarded, despite the fact that they would have had other benefits (obviously not all of them, but enough). It's simply natural selection for CPU innovation.

It's incredibly naive to think that only hardware influences software and not vice versa. For instance, who would create a hardware architecture that didn't have pointers? It would simply never happen, because efficient C compatibility is too important.

The problem is that C was given a disproportionately heavy weighting in these decisions. For instance, a tagged memory architecture would show zero improvement on C benchmarks, but it would have been huge for the languages that now dominate the software industry.

> that there is a language substantially better fit compared to C for low-level programming (e.g. embedded, kernel).

The limitations of C are well known (poor bit fields and bit manipulation, poor support for alignment and padding, no modules, poor standard library, etc, etc.).

Zig addresses some of those issues. Ada has been better than C for a long time. A better language than all of these could definitely be designed given enough resources, eg. see the research effort "House" [1].

[1] http://programatica.cs.pdx.edu/House/

Re: To become a good C programmer (2011)

#128

Earlier quoted context omitted.

>That you can program GPUs in a C/C++-like language does not entail that C/C++ is a natural form of expression for that architecture. It's not a matter of what is/isn't a "natural form of expression." The point of C/C++ is to be high-level enough for humans to build their own abstractions over hardware. (sounds like an OS, right?) The success of the design of C/C++ is in that the creators had no knowledge of modern G…

> It's not a matter of what is/isn't a "natural form of expression." The point of C/C++ is to be high-level enough for humans to build their own abstractions over hardware. Sure it matters. If primitives don't map naturally to the hardware, then you have to build a runtime to emulate those primitives, just like GC'd languages do. > The success of the design of C/C++ is in that the creators had no knowledge of modern…

>If primitives don't map naturally to the hardware, then you have to build a runtime to emulate those primitives, just like GC'd languages do.

That's only half the equation. Hardware cannot save you from semantics that are less efficient. To use your example: every GC'd language must have a runtime system track objects, whether that is implemented with or without hardware support. That system constitutes additional overhead -- either precious silicon is used delivering hardware support for GC or clock cycles are used emulating that support. Either way, you're losing performance. C/C++ have semantics that are easy to support, in contrast.

>You cannot run any arbitrary C program on a GPU.

Nor can you run any arbitrary C/C++ program written for Posix on Windows, or a program written for the x86 on a STM32, etc. You have always had to know your platform with C/C++. The point is that they are flexible enough to work very well on many platforms.

>This fact is exactly why GPUs were able to innovate without legacy compatibility holding them back.

GPUs have become a lucrative business precisely because they have begun exposing a C++ interface. Look at how the usage of graphics cards have changed in recenter years.

> If C were so perfectly suited to any sort of hardware, then GPUs would have been able to run C programs right from the beginning, which is not true.

No. GPUs _were not_ general purpose compute devices from the beginning, as you pointed out. You had GLSL, etc. but the interface exposed to programmers was not Turing-complete. From what I gather, GPUs have only had a Turing-complete interface since shader model 3.0, which first appeared in 2004. By 2007, you had nvcc. Today, C++ is very well supported by CUDA. You may as well be saying "You can't run C on a cardboard box, so it's obviously not well-suited to all hardware." Obviously, your hardware needs to expose a Turing-complete interface for a Turing-complete language to be able to run on it.

>The problem is that C was given a disproportionately heavy weighting in these decisions. For instance, a tagged memory architecture would show zero improvement on C benchmarks, but it would have been huge for the languages that now dominate the software industry.

At what cost? As I already pointed out, adding support for VHLLs at the hardware level means you are spending silicon space on that task => languages like C will be slower. Yes, a lot of software is written in JavaScript, Java, and Python, and these languages would benefit from that hardware support. But people using JavaScript, Java, and Python generally are relying on C services (memcached, redis, postgre, etc) to do their heavy-lifting anyway, which you just made slower.

>For instance, who would create a hardware architecture that didn't have pointers? It would simply never happen, because efficient C compatibility is too important.

No. It would never happen because the machine you just described would make a very bad general purpose computer.

>The limitations of C are well known

Yes, they are. But everything you listed isn't substantial. It's C, with a better standard library, standard support for controlling alignment/padding, and modules. That's not significantly different.

Re: To become a good C programmer (2011)

#129
post #105

Earlier quoted context omitted.

Ah, the famous “Ralph Brown’s Interrupt List”. It was actually published as a book: https://www.amazon.com/PC-Interrupts-Programmers-Reference-T...

just curious. this is not relevant nowadays right?

It's relevant for any computer with a BIOS, it's relevant for the coreboot project (although these days in diminishing value).

Re: To become a good C programmer (2011)

#130

Earlier quoted context omitted.

Backward compatibility. Your example would impose additional constraints on the %d specifier that would likely break existing code. What if you want an int immediately followed by literal ”64”?

Oops, I typoed. I said 'new *printf functions'; the example was supposed to be 'printf2("int64: %d64", x)'

I see! That would make more sense, but I still think the inttypes.h macros are a sufficient solution. Implementers and standards influencing users probably aren't too keen on another formatting language when you can implement it as macros that only take another few characters to use.

    printf2("int64: %d64", x);
for example isn't significantly shorter than

    printf("int64: %" PRId64, x);
Perhaps it's easier to read, but when you have to support both, and you're more likely to run into the latter than the former anyway, I think it just adds cognitive overhead to have to consider which formatting language is being used.
Post reply on HN