The reason that I use C many of times is not because of its speed but because it (almost) completely reveals it inner working even when there is clear reason not to do so.
(1) Though it is bad for most of time but still I feel more contended sometimes with it, especially for complex code.
(2) Even if this transparency is at superficial level with optimising compilers, but there are very few high level optimisation applied to C code and that too in the form of loop unrolling, tail call optimisation, loop interchange etc.
Sadly the libc prng is not specified, and thus non-portable. It might work if things are checked on the same kernel and libc combination, or it might not. The Java PRNG is specified and globally portable.
Not sure the title's question was answered. At the end he just said "And all this time we’ve been ignoring the warning message about main not being a function :)"
I remember 20 years or ago writing my first C/C++ function where I popped out to inline ASM. I was like, wow! I'm in complete control of this box! (It was mostly copied code. My ASM-foo is weak) I really liked the fact that I could either code in these really abstract types -- or be concerned with what the stack looks like on entering a function. So I _think_ I know the answer to the question.
Instead of ignoring the error, I was thinking that you could just mangle the link file and make the entry point whatever you want, right? I could have a program that consisted of "void x", then continue along the lines of the articles with the number list.
Heck, once you start pulling the threads apart like this, the entire structure falls apart. Your source code could look like anything you want it to look like. And that's cool.
I believe you could get around the problem of finding the address of the string by pushing 4 (8?)-byte pieces of it onto the stack and then doing "mov esi, esp".
Place your string after a "call" instruction, then when you are inside the call, the address of the string is on the stack, you can pop it in any register you want.
I like this little project of how one person delved into the fun.
But as far as the TA goes, most people who have an interest in C and programming will look at the source and say to themselves "Oh, byte values of machine code being executed, yes very clever but do the assignment again properly."
If that is the case then the education system is thoroughly broken. It is obvious that a person who took the time to do that learned far more than they would than had they copied one of millions of Hello World examples from the internet.
That being said, I wouldn't rule out a bored TA opening the file not seeing a printf and assigning a grade based on submitting something.
Obviously there are some technical difficulties like handling literal values and code sections, but it could be a fun hack, and I've love to see what someone could come up with.
With enough macros you can do anything. I'm not aware of anyone doing this in C, but this is a cool example of doing approximately the same thing in a more easily extensible language: http://wall.org/~lewis/2013/10/15/asm-monad.html
It's possible, but once you're not obfuscating the code - and already depending on OS details when you assume that global data can be executable, whether const or not - I think you may as well just use the inline assembler feature of your compiler. Well, if there is one... MSVC bizarrely doesn't support on x86-64 what was a perfectly good feature on x86.
OK, your one-liner is simple enough that maybe it's worth a few minutes to unpack it here.
Let's begin with that big constant. The values of
89-(0x1F&2846984999544829581>>5*G)
for successive choices of G are: 76 69 76 65 78 68 66 65 84 69 89 74 87. "Obviously" these are character indices; the characters are L,E,L,A,N,D,B,A,T,E,Y,J,W. (I remark that Leland was the first name of the founder of Stanford University and conjecture that the author of the code works at, or studied at, Stanford. And then I look up at the username of the person who posted it and feel a bit stupid.)
Now, what's the argument to putchar? It has the form
11^--G ? thing1 : thing2
so it decrements G, and then if the result is anything other than 11 it evaluates thing1; but if the result is 11 it evaluates thing2 instead. In this case, thing1 is our LELANDBATEY generator and thing2 is 10 (= newline).
So far, so good. One more step out. What comes before the && inside main? It looks like this:
10<putchar(stuff)
and the return value from putchar is (barring I/O failures) the same as what's fed into it. So, putting the above together, when G isn't 12 we'll decrement G, write out a character from LELANDBATEYJW (indexed by G), and this thing will be true; when G is 12 we'll decrement G, write out a newline, and this thing will be false.
Nearly there. Now the whole thing looks like
main(G) { thing_above && main(2+G); }
so when G isn't 12 it will decrement G, write out a character from LELANDBATEY, and immediately call main with G+2 (which is 1 more than G started out as); but if G is 12 on entry to main it will decrement G, write out a newline, and then return (perhaps to a previous stack frame which will also return, and so on until exit).
OK. So, I guess this program is intended to be invoked with no command-line args. Then G (= argc) will be 1. We'll write out characters 0, 1, 2, ..., 10 of the LELANDBATEY string (getting exactly that far) at which point G will be 12 on entry to the next main call. Newline, exit. Done.
(In case it isn't clear: it outputs "LELANDBATEY\n".)
No offence, I hope, but this is really tame compared with typical short-short IOCCC entries. Here's an example from the 22nd IOCCC. It's short enough to tweet.
I remember something similar that enabled you to embed machine code in VB6 programs, which involved a magic constant that was sort of an entry point into a string containing opcodes. I don't remember the specifics, it's been a while, but nowadays it's very likely a horrible no-go anyway because you're executing data.
Still, was a nifty trick that allowed you to get more performance out of a language that wasn't very fast to begin with.
I remember QuickBasic (the precursor of VB: VB 1.0 was effectively QB 8.0) had a CALL ABSOLUTE statement, which let you execute machine code in a string. I used it to great effect in graphics demos, once upon a time.
Wait, what kind of company forces one of their programmers to take an intro level comp sci course? If you're going to let people hire someone to do a job, maybe you should either trust their judgement or have someone senior work with them to fix obvious defects?
I don't know, something about that just didn't sit right with me.
On a possibly comparable note: in C++, programs can be run entirely from the constructors of static global objects ... letting one write a program with
I think that sets the address of main to NULL, so it segfaults as soon as `_start` jumps to `main`. It's known for being one of the smallest compilable C programs.
> My problem solving process is typically the same thing I imagine most programmers do.
I'm afraid I may be a victim of Poe's law here, but this attitude is... distressing. It completely discounts the value of problem solving, which, once upon a time, was the entire point of the profession.
Well more properly python doesn't have a "main" function. You just directly execute the initial script, which will import other modules, define functions and classes, etc, and finally (hopefully) execute something.
Probably not, since this isn't a case where my co worker can just copy paste my code and hope it works for two reasons. The first is I am not entirely sure their testing environment is using 64 bit linux, it could be 32 bit linux since I'm not in the class, I just assumed its 64bit so I could test it on my machine. The next reason is they don't actually have a Hello World assignment at all! The reason I wrote this article is so I could share something I learned, and my co worker (who has already completed the first half of the semester's assignments) could use this as a starting point for how to write his own version for an assignment.
echo 'const int main[]={3850979413,184,3234285568,33554436,29869896,1207959552,1652109,3343384576,3522,1208291072,114887,3343385088,199,1208291072,1869376613,1919899424,169960556};'>t.c&&gcc t.c&&./a.out
[+] [-] fugyk|11 years ago|reply
(1) Though it is bad for most of time but still I feel more contended sometimes with it, especially for complex code.
(2) Even if this transparency is at superficial level with optimising compilers, but there are very few high level optimisation applied to C code and that too in the form of loop unrolling, tail call optimisation, loop interchange etc.
[+] [-] pjmlp|11 years ago|reply
[+] [-] ejk314|11 years ago|reply
I bet these two ideas would go well together.
[+] [-] masklinn|11 years ago|reply
[+] [-] vortico|11 years ago|reply
[+] [-] mmastrac|11 years ago|reply
https://0xcd80.wordpress.com/2011/04/29/linux-x86-shellcodin...
https://code.google.com/p/alpha3/
[+] [-] jzwinck|11 years ago|reply
[+] [-] peteretep|11 years ago|reply
[+] [-] DanielBMarkham|11 years ago|reply
I remember 20 years or ago writing my first C/C++ function where I popped out to inline ASM. I was like, wow! I'm in complete control of this box! (It was mostly copied code. My ASM-foo is weak) I really liked the fact that I could either code in these really abstract types -- or be concerned with what the stack looks like on entering a function. So I _think_ I know the answer to the question.
Instead of ignoring the error, I was thinking that you could just mangle the link file and make the entry point whatever you want, right? I could have a program that consisted of "void x", then continue along the lines of the articles with the number list.
Heck, once you start pulling the threads apart like this, the entire structure falls apart. Your source code could look like anything you want it to look like. And that's cool.
[+] [-] userbinator|11 years ago|reply
On the topic of "executable ASCII", the EICAR test file is an interesting example: http://en.wikipedia.org/wiki/EICAR_test_file
[+] [-] Spl3en|11 years ago|reply
Place your string after a "call" instruction, then when you are inside the call, the address of the string is on the stack, you can pop it in any register you want.
[+] [-] SixSigma|11 years ago|reply
But as far as the TA goes, most people who have an interest in C and programming will look at the source and say to themselves "Oh, byte values of machine code being executed, yes very clever but do the assignment again properly."
[+] [-] VBprogrammer|11 years ago|reply
That being said, I wouldn't rule out a bored TA opening the file not seeing a printf and assigning a grade based on submitting something.
[+] [-] vortico|11 years ago|reply
[+] [-] lmm|11 years ago|reply
[+] [-] comex|11 years ago|reply
[+] [-] Someone|11 years ago|reply
[+] [-] sirclueless|11 years ago|reply
[+] [-] lelandbatey|11 years ago|reply
For other obfuscated fun, see this poem/tree printer in 505 bytes[0], or this program:
[0] - https://github.com/lelandbatey/tiny_tree_printer[+] [-] gjm11|11 years ago|reply
Let's begin with that big constant. The values of
for successive choices of G are: 76 69 76 65 78 68 66 65 84 69 89 74 87. "Obviously" these are character indices; the characters are L,E,L,A,N,D,B,A,T,E,Y,J,W. (I remark that Leland was the first name of the founder of Stanford University and conjecture that the author of the code works at, or studied at, Stanford. And then I look up at the username of the person who posted it and feel a bit stupid.)Now, what's the argument to putchar? It has the form
so it decrements G, and then if the result is anything other than 11 it evaluates thing1; but if the result is 11 it evaluates thing2 instead. In this case, thing1 is our LELANDBATEY generator and thing2 is 10 (= newline).So far, so good. One more step out. What comes before the && inside main? It looks like this:
and the return value from putchar is (barring I/O failures) the same as what's fed into it. So, putting the above together, when G isn't 12 we'll decrement G, write out a character from LELANDBATEYJW (indexed by G), and this thing will be true; when G is 12 we'll decrement G, write out a newline, and this thing will be false.Nearly there. Now the whole thing looks like
so when G isn't 12 it will decrement G, write out a character from LELANDBATEY, and immediately call main with G+2 (which is 1 more than G started out as); but if G is 12 on entry to main it will decrement G, write out a newline, and then return (perhaps to a previous stack frame which will also return, and so on until exit).OK. So, I guess this program is intended to be invoked with no command-line args. Then G (= argc) will be 1. We'll write out characters 0, 1, 2, ..., 10 of the LELANDBATEY string (getting exactly that far) at which point G will be 12 on entry to the next main call. Newline, exit. Done.
(In case it isn't clear: it outputs "LELANDBATEY\n".)
No offence, I hope, but this is really tame compared with typical short-short IOCCC entries. Here's an example from the 22nd IOCCC. It's short enough to tweet.
See http://www.ioccc.org/2013/endoh3/hint.html for more about this; it interprets tunes written in a simple musical notation and generates raw audio data.[+] [-] ygra|11 years ago|reply
Still, was a nifty trick that allowed you to get more performance out of a language that wasn't very fast to begin with.
[+] [-] evincarofautumn|11 years ago|reply
[+] [-] wheaties|11 years ago|reply
I don't know, something about that just didn't sit right with me.
[+] [-] Kudos|11 years ago|reply
[+] [-] unknown|11 years ago|reply
[deleted]
[+] [-] ctdonath|11 years ago|reply
[+] [-] mncolinlee|11 years ago|reply
http://en.wikipedia.org/wiki/Duff%27s_device
[+] [-] derefr|11 years ago|reply
[+] [-] vortico|11 years ago|reply
EDIT: Your original post contained
[+] [-] belovedeagle|11 years ago|reply
I'm afraid I may be a victim of Poe's law here, but this attitude is... distressing. It completely discounts the value of problem solving, which, once upon a time, was the entire point of the profession.
[+] [-] mden|11 years ago|reply
An example of that is the article itself which leverages the gained information from SO to solve the real problem.
Also arcane knowledge is not the same thing as problem solving.
[+] [-] ekimekim|11 years ago|reply
[+] [-] dmritard96|11 years ago|reply
[+] [-] ekimekim|11 years ago|reply
[+] [-] jarcane|11 years ago|reply
[+] [-] Buge|11 years ago|reply
[+] [-] b0b_d0e|11 years ago|reply
[+] [-] ecesena|11 years ago|reply
[+] [-] 0x44|11 years ago|reply
[+] [-] LukaAl|11 years ago|reply
[Edit]
Less compact but more readable: