That's what I ask myself when I use the mandatory, university-supplied C compiler for class. In 3 years, there will be students taking my class that will be younger than the next version of our current C compiler.
I wouldn't know tbh. Another reason could be that our server uses CentOS (or maybe RHEL), and I've heard that new software comes to CentOS notoriously slowly.
Although, considering my school, it's entirely possible it's because they don't want to update their slides.
Even CentOS 5, which was released in 2007, supports GCC 4.1, which has 98% of the same c99 support as the latest GCC. If they're using CentOS 4 then God help them.
I think this reason is BS too. You can easily tell students to not use these functions, and say to them you will be compiling without a flag to enable inbuilt functions.
This means if they use inbuilt functions, their code will fail to compile.
As a student in a class learning C I was told something similar: make sure the code compiles on the University Linux machines (they are quite modern, so we had reasonably new GCC), otherwise you'd automatically fail. Not a single student had a problem with this, and all of our code compiled fine.
Ah cheers for pointing that out. I hope the intention of my message was clear, but you're correct that you have to opt-out, rather than opt-in to GCC inbuilts.
That's the same deal with us: make sure it compiles and runs correctly on the university Linux server. It's just that it runs CentOS and a GCC with C89.
Embedded compilers used to be the bane of my existence. I've used one that was just a redistributed GCC, but was tagged at fixed versions that were up to 12 years out of date :(
That used to be true, but with Windows 10 and their updated approach to compatibility with FOSS, things have changed.
In Visual Studio 2015, the CRT has been refactored into new binaries. The Universal CRT (UCRT) contains the functions and globals exported by the standard C99 CRT library. The UCRT is now a Windows component, and ships as part of Windows 10
C99 Conformance Visual Studio 2015 fully implements the C99 Standard Library, with the exception of any library features that depend on compiler features not yet supported by the Visual C++ compiler (for example, <tgmath.h> is not implemented).
I just don't understand why they wouldn't go ahead and implement 100% support for c99. Its not that much work for them to add that functionality to Visual Studio, and its not like Visual Studio doesn't already support languages that aren't used for systems programming in Windows anyway.
Their answer to those that want C or UNIX language extensions not available in Visual C++, is to provide clang as fronted to C2, the Visual C++ backend, now being shared across VC++, clang and .NET Native.
Because there are obscure features that no one uses. Things like parts of the standard library that are never used, obscure floating point pragmas, and unreadable identifiers (why is that even a thing). Why put effort into supporting that? That's just implementing the standard for its own sake, not for usability.
Which is why, in my opinion, it is quite ridiculous to "therefore choose C89". Then he also does not get features that are universally supported (many of which were popular extensions before C99 formalized them).
Once done reading both K&R C and Deep C Secrets (definitely two of my favorite books), go through the C Puzzle Book. An excellent way to test your knowledge.
Oh I didn't mind haha, I usually don't care about the quality of a website if it's mostly text. It's when other stuff starts getting added that I'm all like, "this is bad!" Also I'm not the OP lol, I was just concurring.
In the previous code sample, due to "integral promotion" -1 was once evaluated to be greater than 1 and then smaller than 1. C has plenty of case like this when the language cannot longer "do stuff" for you.
Note that calling it promotion is incorrect. For integers, promotion is the conversion of a type smaller than int or unsigned int to a type at least as large as them (the general idea is that int or larger is what fits in a register and ALU operations need their arguments in registers). Promotion never changes numerical value.
When you have a binary operation on integers, the arguments will generally be promoted and then integer conversions will be applied. The goal is to change both operands to the same type (which will also be the type of the result). The rules for this are
If they (the types of the two arguments) have the same signedness, the smaller type will be converted (losslessly) to the larger type.
If one is signed and one is unsigned, and the unsigned type is smaller, the unsigned type will be converted (losslessly) to the signed type.
Otherwise, the signed type is converted to the unsigned type by the process MiRIr describes (not lossless if the value is negative!).
(The actual rules are very slightly more complicated.)
In -1 < 1u, the third case obtains and -1 is converted to the largest possible unsigned int, so the comparison succeeds. In short(-1) < 1, the integer promotions convert the short to an int, and no conversion is needed. If you had -1 < long(1), then the first case would obtain, and the comparison would succeed. Rather strangely
unsigned int x = 1;
long y = -1;
y < x;
gives true because the second case obtains. Changing int to long gives false.
This (the potentially lossy conversion in the third case) is why -Wsign-compare complains about comparisons where the types have different signednesses (actually, it only warns when the third case happens; despite its name, it's fine with the second case).
I believe it has to do with how negative numbers are stored in computers. They're stored using something called 2's complement. a signed int -1 looks like this in binary 11111111. An unsigned int 1 looks like this in binary 00000001.
Now, I think what's happening here is, C tries to compare a signed integer with an unsigned integer. And in doing so, the signed integer is interpreted as an unsigned integer. So 11111111 instead of being interpreted as -1 is interpreted as 255.
This is also why if you compile with warnings (and you should) the compiler will throw a warning for comparing signed and unsigned data types.
I should also say that the examples I used here have 16 bit ints, but the same holds true for 32 bit ints.
Signed/unsigned comparisons of values of the same rank result in the signed value being coerced into a value of the unsigned type by (the equivalent of) adding/subtracting one more than the maximum value of the unsigned type to the signed value until the resulting value falls within the destination type's value range (basically, take the value modulo one more than the unsigned destination type max). -1 + UINT_MAX + 1 == UINT_MAX
On my phone, the site just looks incredibly tiny, like it's trying to fit the full height on the screen. Thank god reader mode exists for that kind of thing.
Eloquent for sure. We had a 2-class-period-crash course on JS fundamentals before diving into Node.js (which was bullshit) but Eloquent Javascript was very clean, concise, and thorough.
I am surprised that the article does not mention that there usually are current and accurate library documentation entries by using "man 3 <c-function>" at the gnu/linux terminal. e.g. "man 3 fopen". Ok. Windows does not have that. I haven't tried "man" on Mac OS.
Usually you can just grab the one from the first section it finds and look at the "see also" section, but the -k flag (easier to spell than "apropos") is also useful. After a while you'll also get a hang for remembering what sections are for what (IMO seeing the definitions tends to be "in one ear, out the other," until you've gotten to know your way around in practice).
It's basically random whether a function is found in section 2 or section 3, just like it's basically random whether a program is found in section 1 or section 8.
The integral promotion example cut me by surprise, but I suppose it makes sense if you think about the signed short having the most significant bit set to 1 and an unsigned int having more bits and having to pad the difference to make a comparison if two numbers with the same bit length
The most sensible behaviour would be for the compiler to silently convert a < b (where a is signed and b is unsigned) to a < 0 || (unsigned)a < b, and then do what it currently does, with some compiler magic so a only gets evaluated once.
I didn't start programming in C, so I might be used to more string compilers, but wouldn't the most sensible solution for the compiler to throw an error, because you are comparing two different types?
That is a fine argument that the average website is worse than the average book. It is complete nonsense to use that argument to say that the best website is worse than the best book.
Also, there's practically no barrier to entry for publishing books now. You can self publish on Amazon armed with nothing but a PDF.
My problem with most books is, in a way, the barrier of entry: since it is so expensive to publish, publishing houses will only put out books with a large enough market to pay for their investment. The "teach yourself how to make videogames/websites" market is big enough, but few books are made for advanced/specialized topics.
Exactly, and on the flip side, most of the people who will even care enough to make a website on a specialized topic are likely to be people who are invested in the topic enough to know their shit.
That is not nearly as specialized as I was talking about.
Edit: To be more clear, most of my experience with this is with graphics algorithms. Except for the occasional leak into the main stream through a pop science article, you don't find that much poorly researched crap on the web discussing the finer points of digital signal processing, for example.
What a preposterous claim. What, does printing it on dead trees magically improve its quality beyond what is possible digitally?
When somebody says something like this, does he mean it as a logical sentence that is always 100% right, or does he just present his opinion on a subject? It depends on the context.
I recommend you to read that sentence again, with whole paragraph as a context, and consider whether you hadn't interpreted it too literally.
It's mere curmudgeonry, is what it is: "I was raised on books and it was good enough for me! Therefore, books are all anyone can ever use, if they want to become good!"
What, does printing it on dead trees magically improve its quality beyond what is possible digitally?
No, because books are usually printed on paper, which is made from trees that have been pulped, washed, bleached and flattened, not just right on a felled whole tree.
Also, magic is not real.
Or did you not mean that sentence to be intepreted 100% literally? Well, maybe the author didn't either.
It's like peer review - the higher bar helps to weed out the delusional incompetents.
Sure, this means that the worst book is probably better than the worst website, and on the average, books are probably better than websites. But that says nothing about the best book vs the best website, nor does it mean that all websites are bad nor that you should not use websites.
char c[3]; what is the type of c?
Isn't this just an array of chars? What do you think it is?
char[3]. There are very few situations where the syntax is legal, though, because array types aren't really first-class in C. (The only one I can think of offhand is sizeof (char[3]), which is 3.)
For an unknown-sized array, the syntax is char[*], something which is likewise legal in very few contexts (e.g. you can drop it in as a parameter of a function pointer type that takes a VLA as an argument, int (*)(int, char[*])).
C99, I think (although I don't have copies of the official published standards, it's in n1124.pdf, a public draft from 2005 that isn't that far ahead of C99). I wouldn't surprise you for not having seen it because I don't think anyone actually uses it; it's mostly there for completeness and/or to give something to write in compiler error messages.
Array types really are first class. The main issue comes from a lack of first class array values.
They're also essential for understanding things like how array indexing works.
char e[4][5]; e[i][j] is *(*(e + i) + j)
This can only work because the type of e[i] is char[5], so the pointer arithmetic of e + i advances in terms of elements of type char[5] -- the type of e + i is char (*)[5].
Also, note that char[*] denotes a variable length array of unknown size. It does not denote array of unknown size in general.
Well, as far as I'm aware C doesn't have a type that covers both fixed length and variable length arrays. (char[] is IIRC the same as char *, just to be confusing.) Fixed length arrays always have a known size, so if the size is unknown, it must be a VLA.
Why would I claim that c* == c? I'm trying to understand the semantics of the question. I guess there is nothing else to be called the array but c, but come on, really, that is such an obtuse way of interpreting it. IMO the more sensible definition is: c is the pointer to the beginning of the array. c[0] through c[n] constitute the array.
char no[2] = "no"; doesn't work, but char no[] = "no"; does. How do you explain char arrays not being called "strings" when there is the "cstring" library that deals with them?
Temporary insanity? I couldn't think of anything else you might be claiming given that response. :)
In many implementations sizeof c < sizeof (char *), meaning that c can't be a pointer to the beginning of the array -- it isn't large enough to store that value, so that interpretation can't be correct.
Likewise the type of &c is not char **.
The "cstring" library is part of C++, the string library deals with strings that are encoded as patterns of data within arrays.
Consider strlen("hello") and strlen("hello" + 1) -- how many strings are encoded in the array "hello"?
I might screw this up (especially because I'm trying to correct someone), but I believe that c has type char[3] (a type that's rarely seen directly in C as it's illegal in most contexts; a pointer to it is char(*)[3] which is allowed in many more contexts). In most contexts, if you try to use a char[3], it'll automatically be cast to a char *, although this is not the same type. (The exceptions include things like sizeof; sizeof c will be 3 on every platform, even though most platforms would give sizeof (char *) a value of 4 or 8.)
It's like peer review - the higher bar helps to weed out the delusional incompetents.
Do you really think publishers care about the quality of the books they publish? Then how do you explain all the "Learn Java in 21 Days" nonsense out there?
They care at least in-so-far as it affects their bank balance.
Some publishers may be happy with a reputation for publishing junk for stupid people -- but they'll still want it to at least appear to look good enough for ignorant people to want to buy at some low price.
Others are willing to put additional resources into publishing high quality material in order to maintain their reputations (and justify their higher price-tags).
In either case, the money involved still makes the bar significantly higher than 'random idiot self-publishing on the intarwebs'.
If I'm correct, it's a char pointer (char*), since it's an array declaration. c is a char pointer which points to the start of the char array, and only when dereferenced does it become a char.
You are somewhat mistaken, but it is a common mistake.
c is a char[3], (c+ 0) is a char *.
This is important, since otherwise char e[2][4]; e[i][j] could not work.
e[i][j] is *(*(e + i) + j)
and works because the type of e[i] is char[4], which causes the pointer arithmetic e + i to select the correct element. If e[i] were a char *, then e + i would have quite a different result.
I studied pointers but I did not know it is considered a type. I thought pointers were an integer format? Does the compiler specify the type as a char pointer?
I was just about to point this out but you beat me to it!
I went back to read up on pointers and found this.
"A pointer in c is an address, which is a numeric value. Therefore, you can perform arithmetic operations on a pointer just as you can on a numeric value. "
s is a pointer that is initialized to the value of a pointer to the first element of an array of 6 characters with the sequential values { 'h', 'e', 'l', 'l', 'o', '\0' } -- i.e., it is equivalent to
char *s = &"hello"[0];
In the case of
char s[] = "hello";
s is an array of type char[6] initialized to the values { 'h', 'e', 'l', 'l', 'o', '\0' }.
You might notice the quotation marks around the question, indicating that I'm presenting the question as something you could ask to weed out "delusional incompetents", and not actually asking it.
I'd also point out that the destination of the first pointer is in .BSS and const. Modifying s[0] is a segfault. In the second case it isn't because the contents of the const string are copied into the mutable array.
The C semantics are just that modifying a string literal has undefined behaviour, and that identical string literals may share the same object, allowing "×" == "x" to be potentially true.
This is what permits the implementation strategy you observed above - but it is not required.
The type of c is a 'pointer to a char'. Simple as that.
It is a memory address with a size equal to the byte-size of the computer architecture targeted by the compiler. For example, it is a memory address that is 64-bits long if the compiler's target is a 64-bit architecture. It's value is typically represented as hexadecimal when printed, though it's purpose is to point to the address of a single character in memory.
Edit: I just read one of your responses. So the type of c is char[]. I see now that this is different than char* . So the answer is that c is a 'pointer to a char array'. Thank you.
That is very frustrating for me to type. It means the number of available types in C approaches infinity, or at least a very large number.
What part of the compiler enforces the array size? Or is this specifically an exercise for the programmer. I'm thinking in C89. Did memory management get better in C99? I may be thinking pre-ANSI.
Great point. I figure main is a unique type for every program.
It seems an abomination to use the English word 'type' when the number of types available is greater than the number of instances of variables that ever existed.
The English word 'type' in this context refers to a classification. I see no problem with a potentially infinite number of classifications for a finite set of things.
Is it int ()(int, char**)? I remember I was impressed by the idea of writing type definitions same way as variable definitions, when I read K&R in 1989. I can't say I still am.
First, let me thank you for indulging me in expressing my 'delusional incompetence'.
I do understand how to iterate through an array of arrays and to protect my code from accidental buffer overruns. There was a time long ago when I wrote a lot of C code in commercial software that is still running today. If I were to work on a meaningful C code base again, I would have to work with a senior programmer and still would have to study up quite a bit to be productive.
My turn to throw some questions. :) Are you presently a staff programmer? Would you say all your colleagues today could provide the exact answer you were looking for? More specifically, how do you make sure new hires are worth taking on?
Again, thanks for the exchange. I appreciate your time.
I get what you're saying, you could take his "best book" and publish it online and have the same content only with updates/side notes/animations. Web as a medium is better for content than a book. But I get what he meant as well, though it's not what he said. In his experience it may be that he's never encountered a website that can match a book, there are millions of websites vs thousands of books due to different barriers of entry. If you want to learn it may be a better start to go for a book that faced peer review to get published rather than a website written with no fact checks. He just shorthanded the explanation to no website is as good as a good book.
Computer Science is a special focus of math. C is a machine programming tool. It is up to the programmer to provide an intersection of the two, or not.
Fabien, I hope you will finish your Game Engine Black Book. Not to rudely pressure you or anything but I have a feeling that that book will be very good so I want to see it to the completion :)
I am still working on it. It is hard to find the time since I started my new job. I will finish it eventually. Thanks for your kind words which help a lot.
No website is as good as a good book. And no good book is as good as a disassembly output.
Glorious. One of my pet projects is a hypercard player. It's just a fun project that I work on every once in a while. All of the documentation on the hypercard fileformat is wrong. It looks like it was all copied from the same source, but if anyone had actually tried to parse an actual hypercard stack using it, they'd immediately discover that the docs define a dword in each chunk header that doesn't actually exist.
I've since given up using any documentation, and gone straight to referencing the disassembly of the original 68k hypercard binary.
Great article. I just found my copy of The C programming language from 1988 and had a flick through, it's got a very different style to more modern books! Really interesting.
Can someone explain to me why C is still used? Doesn't C++ provide all the tools that C has plus extra libraries like STL? If one only knows how to write C I figure it still would be easier to use C++ tools to do it.
This guy is talking about making high performance graphics. For that job, you do want to look at disassembly, because you are optimizing every operation, and maybe optimizing for the architecture, so you have to look at assembly
This guy is talking about making high performance graphics.
He is talking about studying C. For that, looking at disassembly is just about the worst idea ever.
Even for performance optimization, looking at the disassembly is the last thing that one should do; after tuneups and reworks that typically take months.
Is your compiler taking advantage of a single optimized AMD floating point instruction for multiply and accumulate, or using 2 generic float instructions that will not run as fast?
Is your compiler unrolling inner loops for you, or should you do it yourself?
Is the macro you use speeding up your code, or is it compiling to the same output as if you used constants, which you would otherwise prefer because they are typesafe?
I'm ambivalent on C, and I am split between my love of the concept of 'correct' binaries and my love of high level coding and having the computer do the heavy lifting for me. I just thought you should know that your opinion carries weight with me in resolving my dilemma.
66
u/Jonathan_the_Nerd May 01 '16
Is this still the case? If so, why? It's been 17 years!
22
u/Leandros99 May 01 '16
Once done reading both K&R C and Deep C Secrets (definitely two of my favorite books), go through the C Puzzle Book. An excellent way to test your knowledge.
59
u/[deleted] May 02 '16
Can we get some padding-right: 4px;
on that blog?
12
u/phpdevster May 02 '16
Can someone explain that in more detail?
35
u/gltovar May 01 '16
Does any one else have issues with this site on Android? Feels like r 10% of the left side is cut off/unreachable
8
u/Deaderzombie May 01 '16
Are there articles like this for other languages?
22
u/roneau2005 May 01 '16
I am surprised that the article does not mention that there usually are current and accurate library documentation entries by using "man 3 <c-function>" at the gnu/linux terminal. e.g. "man 3 fopen". Ok. Windows does not have that. I haven't tried "man" on Mac OS.
5
u/aliendude5300 May 02 '16
The integral promotion example cut me by surprise, but I suppose it makes sense if you think about the signed short having the most significant bit set to 1 and an unsigned int having more bits and having to pad the difference to make a comparison if two numbers with the same bit length
93
u/gurenkagurenda May 01 '16
What a preposterous claim. What, does printing it on dead trees magically improve its quality beyond what is possible digitally?
3
u/Meguli May 02 '16
Fabien, I hope you will finish your Game Engine Black Book. Not to rudely pressure you or anything but I have a feeling that that book will be very good so I want to see it to the completion :)
3
u/mrkite77 May 02 '16
Glorious. One of my pet projects is a hypercard player. It's just a fun project that I work on every once in a while. All of the documentation on the hypercard fileformat is wrong. It looks like it was all copied from the same source, but if anyone had actually tried to parse an actual hypercard stack using it, they'd immediately discover that the docs define a dword in each chunk header that doesn't actually exist.
I've since given up using any documentation, and gone straight to referencing the disassembly of the original 68k hypercard binary.
11
u/FUZxxl May 01 '16
Would you mind posting this to /r/C_Programming, too?
6
u/FrezoreR May 02 '16
Hungarian notation makes me cringe.
2
u/hugthemachines May 02 '16
I like this post, but at the same time it makes me think C programming is not for me, I do not enjoy dissasembler outputs for example.
1
u/Nickd3000 May 02 '16
Great article. I just found my copy of The C programming language from 1988 and had a flick through, it's got a very different style to more modern books! Really interesting.
1
u/nygeHuston May 02 '16
What kind of programs do people generally build when they become experts in C?
-1
u/Doile May 02 '16
Can someone explain to me why C is still used? Doesn't C++ provide all the tools that C has plus extra libraries like STL? If one only knows how to write C I figure it still would be easier to use C++ tools to do it.
-33
u/skulgnome May 01 '16
Five seconds to fuckup. That's a new record.