First part of your explanation is OK - let's say we need to unroll a loop for efficiency. And we decide to unroll it so it has 8 statements inside the loop. So, assuming count>0, we would do something like this (using dots to show indentation because "ecode" eats up leading spaces):
void copy(char *from, char *to, int count) { ..int n = count / 8; ..int i;
That's a standard loop-unrolling for you. Duff's Device just shortens it. How? The switch statement jumps into the loop to a point where we first handle the "leftovers", and then we execute the loop (count/8) times, each time copying 8 elements, thus copying (count/8)*8 elements in the loop (which, because of integer division is not equal to count unless count%8==0, that's why the leftovers).
Thus, the part where you talk about count being excatly divisible by 5, 6, 7, etc., is wrong. The switch statement only checks the remainder of count when divided by 8.
This may be wrong too. In that case, please feel free to correct me.
I was an undergraduate student at Indian Instutute of Technology, Kanpur (where this project was developed), and have been to Bithoor many times.
The whole village consists almost exclusively of very poor people, who couldn't care less about this technology.
The middle class you speak of, doesn't exist in Bithoor. In slightly bigger villages/towns, it does.
I grew up in a village which was bigger than Bithoor, and had no access to computers till I was an undergrad at IIT Kanpur. I think of myself all the time when I think of such technology introduced in villages, and how I could have benifitted from it.
Definitely a good thing. But maybe more people would benifit if there was more effort in social/civic education in cities in India, and villages were more self-reliant. And of course, somehow the poor people in the villages didn't starve and suffer from innumerable diseases.
-D: implies deep. This upgrades the packages that you didn't directly install (but which were installed as a dependency of the packages you installed). While this may seem to be a good idea, it may break things. For example: if you installed xine, which depends on libdv, portage will install libdv. Now, if you do an emerge -D world, and a new version of libdv is available, it will install that. xine still depends upon the old version though, so running it will give you an error as the old library is not found. Solution? Install gentoolkit and then use revdep-rebuild to make sure all broken dependencies are rebuilt. Or don't use -D at all.
-U: as I said before, you probably don't want this, as it will not "downgrade" some packages when it may be necessary to do so (bugs, security issues, broken ebuilds, etc.).
First of all, it is a pretty bad idea to use -U (--upgradeonly), because if the latest version of a package has some bug (either in the software itself, or in the ebuild), then you may well need to downgrade it (and portage will downgrade it [if needed] if you use the -u option). emerge -u is the Right Way.
For the OP, emerge -upv world to see what will be upgraded, and then do an emerge -uv world to actually upgrade it (or you can upgrade only the packages you want to upgrade from the list).
emerge -upv tells you which packages will be upgraded, and with what options (USE flags in Gentoo speak). -p is for pretend, while -v means verbose. Always a good idea before going ahead and doing the actual upgrade.
Of course, with Gentoo, you never need to download the new distribution to make sure you stay current. Just do emerge -u world (after an emerge sync), and you have the latest version.
Actually, pointer casts on memory allocation functions (that return void *) can help detect errors where you change the type of a variable you're assigning to. Since the casts will now mismatch, the compiler will signal a warning/error, thus pointing out your mistake. On the other hand, not including the right header can be checked for using prototypes. GCC has options to flag functions without prototypes with warnings and errors.
I will use malloc for my examples below, but the same thing could be said for alloca.
There are various ways to use malloc:
type *v; v = (type *) malloc(n * sizeof(type));
type *v; v = (type *) malloc(n * sizeof *v);
type *v; v = malloc(n * sizeof *v);
1. is what I see many programmers use. And it is error prone to
forgetting to #include stdlib.h
if one changes the type of v later on, then forgetting to change the type inside the malloc call
2. goes halfway, and is thus if you forget to #include stdio.h, compiler may not be able to issue a warning since you are casting the result of malloc to some type, and thus compiler may assume you know what you are doing. It will default to malloc's return type as int since there is no prototype in scope. Likely result: core dump when you run the program.
3. is the preferred way to do it IMHO. You don't need to worry about forgetting to #include sdtlib.h, since a decent compiler will issue a warning, and you don't need to worry about changing the type of v later on and forgetting to update the malloc call. Also, it is the most elegant (and easy to read) of the three calls.
About the only disadvantage I see is having to write all this stuff everywhere. It tends to require breaking malloc statements into multiple lines, and the like.
Exactly. And that is one reason to do away with it and use malloc the way it is used in 3. above.
That said, this is a book about Linux programming, not C programming. Portable C programming wouldn't even use something like alloca, so I'd consider it perfectly valid to use techniques that rely on a platform-specific environment.
Agreed. But I still can't understand why one would use alloca and casts to (type *) on void * object when the C standard guarantees that malloc is available on all portable implementations (even C89). When Linux has malloc, there is no reason to use alloca, particularly when one is doing it in a textbook. alloca isn't even POSIX.
Leaving out the prototype "works", but as you said, it's gross. The function parameters can be named anything (since they are just that: function parameters). But the names argc and argv are used by convention.
I haven't seen the book, but I checked some examples from the book.
I can see the following "problems" with some of them (if I am wrong, someone please correct me):
ch02-printenv.c:
#include <stdio.h>
extern char **environ;
Shouldn't there be a #include <unistd.h> after the #include <stdio.h>? The extern variable environ is available only if unistd.h has been included. While I am talking about this example, it could have used int main(void) instead of...(int argc, char **argv) (like he does in ch03-getline.c).
ch03-getline.c:
printf("(%lu) %s", size, line);
size is declared size_t, so it should be printed with %z (C99 only, IIRC), or it sould be cast (unsigned long) size.
ch03-memaddr.c:
uses global variables, when simply adding two parameters to afunc will do the job. I know it's a trivial example, but global variables are bad in general, and certainly avoidable in this case.
casts the result of alloca when there is no need for it. In fact, the cast will remove the warning the compiler might give if someone forgot to #include <alloca.h>.
main(i){(10-putchar(((25208>>3*(i+=3))&7)+( i ?i-4?100:65:10)))?main(i-4):i;}
The above invokes undefined behaviour, because: 1) no prototype for putchar() 2) main either takes two arguments (int, char ** or equivalent), or none. In C99, you would need to declare int main(int argc, char *argv[]) 3) You don't return a value from main() 4) It assumes ASCII character set. There might be others, ask news:comp.lang.c:)
Hmm. Doesn't make full sense to me this way.
First part of your explanation is OK - let's say we need to unroll a loop for efficiency. And we decide to unroll it so it has 8 statements inside the loop. So, assuming count>0, we would do something like this (using dots to show indentation because "ecode" eats up leading spaces):
That's a standard loop-unrolling for you. Duff's Device just shortens it. How? The switch statement jumps into the loop to a point where we first handle the "leftovers", and then we execute the loop (count/8) times, each time copying 8 elements, thus copying (count/8)*8 elements in the loop (which, because of integer division is not equal to count unless count%8==0, that's why the leftovers).
Thus, the part where you talk about count being excatly divisible by 5, 6, 7, etc., is wrong. The switch statement only checks the remainder of count when divided by 8.
This may be wrong too. In that case, please feel free to correct me.
s/Instutute/Institute
argh!s/benifit/benefit
s/benifitted/benefited
I was an undergraduate student at Indian Instutute of Technology, Kanpur (where this project was developed), and have been to Bithoor many times.
The whole village consists almost exclusively of very poor people, who couldn't care less about this technology.
The middle class you speak of, doesn't exist in Bithoor. In slightly bigger villages/towns, it does.
I grew up in a village which was bigger than Bithoor, and had no access to computers till I was an undergrad at IIT Kanpur. I think of myself all the time when I think of such technology introduced in villages, and how I could have benifitted from it.
Definitely a good thing. But maybe more people would benifit if there was more effort in social/civic education in cities in India, and villages were more self-reliant. And of course, somehow the poor people in the villages didn't starve and suffer from innumerable diseases.
</rant>The correct formula should be:
Number of bytes/second*8 = Number of bits/second
And not:
Number of bytes/second = Number of bits/second*8
This is a new kind of "spelling" errors on slashdot now. One more reason to subscribe? :)
Interestingly, a byte may not necessarily be 8 bits everywhere. The C standard for example allows a byte to be any number of bits (>=8).
Couple of points:
-D: implies deep. This upgrades the packages that you didn't directly install (but which were installed as a dependency of the packages you installed). While this may seem to be a good idea, it may break things. For example: if you installed xine, which depends on libdv, portage will install libdv. Now, if you do an emerge -D world, and a new version of libdv is available, it will install that. xine still depends upon the old version though, so running it will give you an error as the old library is not found. Solution? Install gentoolkit and then use revdep-rebuild to make sure all broken dependencies are rebuilt. Or don't use -D at all.
-U: as I said before, you probably don't want this, as it will not "downgrade" some packages when it may be necessary to do so (bugs, security issues, broken ebuilds, etc.).
Other than that, you are right. So, just do:
For the OP, emerge -upv world to see what will be upgraded, and then do an emerge -uv world to actually upgrade it (or you can upgrade only the packages you want to upgrade from the list).
emerge -upv tells you which packages will be upgraded, and with what options (USE flags in Gentoo speak). -p is for pretend, while -v means verbose. Always a good idea before going ahead and doing the actual upgrade.
Of course, with Gentoo, you never need to download the new distribution to make sure you stay current. Just do emerge -u world (after an emerge sync), and you have the latest version.
I will use malloc for my examples below, but the same thing could be said for alloca.
There are various ways to use malloc:
1. is what I see many programmers use. And it is error prone to
2. goes halfway, and is thus if you forget to #include stdio.h, compiler may not be able to issue a warning since you are casting the result of malloc to some type, and thus compiler may assume you know what you are doing. It will default to malloc's return type as int since there is no prototype in scope. Likely result: core dump when you run the program.
3. is the preferred way to do it IMHO. You don't need to worry about forgetting to #include sdtlib.h, since a decent compiler will issue a warning, and you don't need to worry about changing the type of v later on and forgetting to update the malloc call. Also, it is the most elegant (and easy to read) of the three calls.
About the only disadvantage I see is having to write all this stuff everywhere. It tends to require breaking malloc statements into multiple lines, and the like.
Exactly. And that is one reason to do away with it and use malloc the way it is used in 3. above.
That said, this is a book about Linux programming, not C programming. Portable C programming wouldn't even use something like alloca, so I'd consider it perfectly valid to use techniques that rely on a platform-specific environment.
Agreed. But I still can't understand why one would use alloca and casts to (type *) on void * object when the C standard guarantees that malloc is available on all portable implementations (even C89). When Linux has malloc, there is no reason to use alloca, particularly when one is doing it in a textbook. alloca isn't even POSIX.
Surely you meant void main instead of int main? Yup, you are correct. It should not be cast to unsigned long, however.
Then how should it be done in C89? C89 does not define a format specifier for size_t objects. All it says about size_t is that it's an unsigned type.
I can see the following "problems" with some of them (if I am wrong, someone please correct me):
ch02-printenv.c:
Shouldn't there be a #include <unistd.h> after the #include <stdio.h>? The extern variable environ is available only if unistd.h has been included. While I am talking about this example, it could have used int main(void) instead of ...(int argc, char **argv) (like he does in ch03-getline.c).
ch03-getline.c:
size is declared size_t, so it should be printed with %z (C99 only, IIRC), or it sould be cast (unsigned long) size.
ch03-memaddr.c:
uses global variables, when simply adding two parameters to afunc will do the job. I know it's a trivial example, but global variables are bad in general, and certainly avoidable in this case.
casts the result of alloca when there is no need for it. In fact, the cast will remove the warning the compiler might give if someone forgot to #include <alloca.h>.
I haven't checked other examples.
Discovery of Uranus comes to mind.
Oops. I meant Neptune.
That will be good result, invalidate prediction - Michelson Morley experiment is what you are talking about (which I used as an example above).
Bad result: experiment itself is designed badly, and the results should not be trused.
Good result: experiment is designed well, and therefore one can trust whatever results come out of it.
Reflections on Trusting Trust by Ken Thompson.
Nope, getting the "spelling" of /. incorrect: priceless :)
FWIW, NASA ADS returns 22 abstracts.
Original post on Google Groups. People might like other posts by Egg Troll too.
This is the link to the PGN file. This has a java applet where you can replay the game.
main(i){(10-putchar(((25208>>3*(i+=3))&7)+( i ?i-4?100:65:10)))?main(i-4):i;}
The above invokes undefined behaviour, because:
1) no prototype for putchar()
2) main either takes two arguments (int, char ** or equivalent), or none. In C99, you would need to declare int main(int argc, char *argv[])
3) You don't return a value from main()
4) It assumes ASCII character set.
There might be others, ask news:comp.lang.c