
Resume in C - brudgers
https://gist.github.com/klange/4042963
======
Aldo_MX
Wow, I didn't know this was valid C code, it's pretty convenient.

    
    
      school_t uiuc = {
          .school   = "University of Illinois at Urbana-Champaign",
          .location = "Urbana, IL",
          .program  = "BS Computer Science",
          .started  = 1251158400,
          .left     = 1336608000,
          .accomplishments = {
              "Minor in International Studies in Engineering, Japan",
              "Focused on systems software courses",
              NULL
          }
      };

~~~
lcampbell
It's a C99 feature (I think?) -- designated literals. They're absolutely
wonderful.

~~~
amaterasu
It's supported by GCC as an extension to C90 too.

~~~
samatman
what does that even mean? Isn't C99 an extension of C90/ANSI? Doesn't GCC
support the whole of C99 as an extension to ANSI?

~~~
masklinn
It means that GCC will allow/support this even if you set it to std=c89 or
std=c90.

~~~
michaelmior
Won't that only be supported in gnu89 or gnu90 mode?

~~~
edmccard
No, it will be supported using -std=c89 or -std=90, unless you also specify
-pedantic.

~~~
michaelmior
Yes, I realized after posting that -pedantic is required for strict standards
compliance.

------
therealdrag0
When I was in university, I did something similar in Python. I printed it off
in color and brought it to a career fair. One guy loved it excitedly. But I
didn't hear back from him :(. And that's the story of how I cam to work in
Java ;)

~~~
afarrell
This is why when you meet someone at a networking event:

0) Have brought a pen or cell phone.

1) Always get their business card or contact info.

2) When you get someone's business card, always write down where you met them
and what you want to ask or show them. Otherwise, you end up with a pile of
cards and no memory of who they were from.

2.1) If you actually had them type their email into your phone, sketch out the
email, but don't send it.

3) follow up within 3 days or you'll forget.

------
newobj

        --- a/resume.c
        +++ b/resume.c
        @@ -118,7 +118,7 @@ void print_job(job_t * job) {
                }
         }
        
        -int main(int argc, char * argv) {
        +int main(int argc, char ** argv) {
        
                int i = 0;
                while (jobs[i]) {
        @@ -127,4 +127,4 @@ int main(int argc, char * argv) {
                }
        
                return 0;
        -}
        \ No newline at end of file
        +}

~~~
lukeasrodgers
For those who don't write C, could you explain what is significant about this
change? I'm guessing the earlier version was some kind of subtle bug?

~~~
tcas

      char * argv
    

is a pointer to a string (or a single character).

    
    
      char ** argv
    

is a pointer to an array of pointers to strings. The latter is used since it
allows for multiple arguments in (the number being `int argc`).

This picture shows the second example in terms of pointers:

[http://www.londonquilters.org.uk/ctext/pic511.gif](http://www.londonquilters.org.uk/ctext/pic511.gif)

~~~
shultays
Wouldn't second simply segfault when you try to access it?

~~~
tcas
Nope, neither will segfault on the initial access.

    
    
      char ** argv
    

is a null terminated array in C according to the C standard. (EDIT: see
clarification below) C doesn't care about types at all and you can abuse this
by casting pointers to different (sometimes incompatible types). The second
argument to main (argv) it set up by the initialization code and has the same
space as a pointer regardless if it's a string, array of strings, struct,
integer etc...

The existing structure will simply be interpreted as that new type like so:

    
    
                    String1       String2    String3     String4
      char ** a2: |0x41414141 |0x42424242 |0x43434343 |0x00000000 |
                  +-----------+-----------+-----------+-----------+
      char * a1 : |41|41|41|41|42|42|42|42|43|43|43|43|00|00|00|00|
      
      printf("%s\n", a1);
      > AAAABBBBCCCC
    

That being said, some compilers (clang) will emit an error on the improper
type, like so:

    
    
      test.c:3:5: error: second parameter of 'main' (argument array) must be of type
            'char **'
      int main(int argc, char * argv)
          ^
      1 error generated.

~~~
pqomdv
We are talking about C and not a specific compiler, so there are a lot of
mistakes in your comment.

char * * is a pointer to a pointer to a char and nothing else, it might be a
NULL terminated array or not at all.

C cares about types. Casting a pointer to an incompatible type or
reinterpreting through an incompatible pointer is not defined in C( undefined
behavior ).

Pointers of different types are allowed to have different sizes. sizeof( char*
) == sizeof( char* * ) is not guaranteed in C.

Also any program whose main is not int main( void ) or int main( int , char* *
) will result in undefined behavior.

All of this is in the latest standard.

Both, segfaulting or running completely normally can be a result of undefined
behavior. That is why we really like to avoid it in C. Thus your advice is
really not good for a modern C.

~~~
tcas
In the case of argv though on main it is defined to be null terminated on
argv[argc] according to the standard. Assuming the pointers are the same size
though what I said will work but is bad practice.

> sizeof( char* ) == sizeof( char* * )

True, I forgot that different architectures/compilers can produce different
pointer sizes. Thanks!

~~~
pqomdv
char* * argv is NULL terminated, my mistake I though you were referring to
that type in general.

------
asveikau
Code review:

* The struct members and variables pointing at string literals should be const.

* People do break this all the time but typedefs ending in _t are reserved by POSIX.

* Your C99 style struct initializers are valid but it's notable that one popular compiler, MSVC, will not like them.

* If we are being idiomatic I would suggest pointer arithmetic to iterate instead of using a counter i.

~~~
amelius
Style review:

* Avoid using NULL in your resume. It has a negative connotation, and makes your resume look bad.

* Make use of as many existing libraries as possible, to show that you're not the kind of programmer that wants to invent the wheel on every occasion.

* Try to obfuscate your resume a little (but not too much!) As it is written here, your reader can easily guess what the program will do, and he/she will not even want to run it anymore.

* #include a portfolio of your work inside your resume.

~~~
evincarofautumn
You had me going for a moment there. I was ready to respond to your comment
about NULL before I realised you were joking.

------
z3t4
This is a hit or miss. Say they are looking for a C coder. A bad recruiter
(most of them) would just discard this as he/she wouldn't even recognize it as
C code, just some junk not fitting into his/her template. A good recruiter
though, or if a recruiter wasn't used - they would see this as smart and
creative and definitely get you an interview.

I've seen companies shutting down/relocated because of bad recruiters
filtering good programmers like this.

~~~
kpmah
Personally, I wouldn't want to work for a company that uses bad recruiters
(and thus probably hires bad programmers), so something like this would be
doing its job.

You don't have to go this far. My CV is a HTML page, and I just refuse to
convert it to Word. It hinders the recruiters who just like to buzzword search
their database.

------
nvader
When I saw the title, I thought it was going to be about pausing and resuming
a thread of execution or some stack.

Could an editor put the slanty thing over the e in the title?

~~~
wrboyce
FYI the "slanty thing" is called an acute accent.

------
alexbecker
Just curious, but why do you use

    
    
      initialize
      while (test) {
        ...
        increment
      }
    

instead of

    
    
      for (initialize; test; increment) {
        ...
      }

------
dangayle
It's cheeky, but then again it _is_ a project you can show someone. Graphic
designers get to make fancy schmancy resumes to impress their potential
employers, so why not programmer? Better make sure there are no bugs in it
though.

~~~
BinaryIdiot
Ah nothing like handing your resume over to a prospective employer and having
it SEGFAULT

~~~
MatthewWilkes
If they'll run unknown code without checking it first that's something you'd
want to know about.

------
dan1234
Reminds me of Major Hayden's man page résumé[0]

[0][http://majorhayden.com](http://majorhayden.com)

~~~
draegtun
Nice. Here's one I always remember (written in Haskell) -
[https://ocharles.org.uk/](https://ocharles.org.uk/)

OCharles originally did it in Perl/Moose and with a module of mine (Acme::URL)
which is how I stumbled across the CV in the first place -
[https://web.archive.org/web/20120119150530/http://ocharles.o...](https://web.archive.org/web/20120119150530/http://ocharles.org.uk/)

------
vbezhenar
Something like #define DATE(month, day, year) ... would help to read dates
without program running.

------
zaroth
Yes, but if i is divisible by 3, you need to print... oh, never mind.

------
X-Istence
I did my entire portfolio as a C++ project at one point. Downside is that
recruiters and managers looking at my site thought something was wrong on my
server and they were seeing the code for the site.

I still have a copy of it online at:
[http://old.bertjwregeer.com](http://old.bertjwregeer.com)

------
philh
For bonus points (or not, depending on the recipient's sense of humour)
construct a resume that would be suitable for the underhanded C contest
([http://www.underhanded-c.org/](http://www.underhanded-c.org/)).

~~~
chii
that would be an interesting way for malware to enter - you submit a seemingly
innocent resume in C, ask the reader to compile it to see it in pretty
colours/formatting. And subtlety pwning the machine in the process.

------
b0t
Just waiting for the resume in Brainfuck

------
srameshc
"They're all while loops because shut up, you're overthinking a joke." Just
curious what is wrong with all the while loops ?

~~~
dtzWill
Nothing, really.

There's an argument that using a 'for' construct groups together the details
of the loop (initialization, the loop condition, iteration update), which can
aid readability.

(You don't have to search the loop body to find how things change between
iterations)

Of course, nothing forces a for() loop to have iteration behavior entirely
dependent on only what's in the 'for'. In my experience this seems to be
discouraged, however, preferring to use 'for' only when there is a predictable
and simple iteration pattern.

In the end, it's just a matter of preference and style. :)

------
bane
This is great fun, which comes along at a nice time since I'm working through
an intro to C class to revive some very stale "real language" skills I've lost
years ago. I've studied through some basic dynamic data structures (linked-
lists, binary trees, etc.) and was quite surprised at both how much of this I
could follow AND how much I learned.

------
allending
Would be pretty awesome to make a Swift playground version of a CV that is
animated and interactive.

------
jlukecarlson
I really liked this project and it inspired me to write something similar in
OCaml. If you are interested the link is here:
[https://news.ycombinator.com/item?id=9226093](https://news.ycombinator.com/item?id=9226093)

------
snorkel
That's pretty great. It's too bad most HR tools would completely screw that
nice formatting, but I'd definitely bring printed copies of that into a dev
role interview! That'd break the ice right away.

------
perdunov
Great idea, but oops... the data structure thing_t is hideous. It is a "god
object" for anything where differently purposed members are union'd. Also,
putting char*'s into a union is a terrible idea.

~~~
masklinn
> It is a "god object" for anything where differently purposed members are
> union'd. Also, putting char*'s into a union is a terrible idea.

They're not differently purposed, the union is just used to define more
contextual labels for equivalent fields, and thus make initialisation more
readable within each domain.

~~~
perdunov
There are three data structures unsystematically blended into one (that is,
one cannot unambiguously tell which fields go into which "virtual" type, and
cannot formally check the correctness). The name thing_t is indicative that
you indeed cannot really tell what that entity is. This kind of data structure
design begs for errors, while being conceptually wrong.

~~~
masklinn
> There are three data structures unsystematically blended into one

The point is that they're not three completely separate data structures,
they're a single data structure with context-dependent field labelling.

~~~
perdunov
I get your point, but how to tell "labelling" from typing? Typing depends on
semantics. This particular example only works out because the types are all
strings, which is a case of sort of loose typing often used in programming. It
could've been like this:

    
    
      typedef struct {
    	union {
    		company_t * company;
    		school_t * school;
    		project_t * project;
    	};
    	union {
    		address_t * location;
    		url_t * url;
    	};
    

etc.

------
jerluc
It would help greatly to add the appropriate accents (aigus) to the title of
this submission, as I misread this to refer to "resume in C" as in "resuming a
suspended continuation in C" :)

------
sloanesturz
It's pretty slick -- although I don't know a lot of recruiters who can convert
unix timestamps to actual dates in their heads!

~~~
asveikau
That's why they run the program, it formats them.

Pasting in code from the internet and running it is a little scary though. I
wonder of we can spot the backdoor here. :P

~~~
pestaa
It's not even running it only. Recruiters need to compile it first. :)

~~~
fit2rule
So it also acts as a good qualified for the company being applied to, then ..
pretty wise. Why work at a place that can't compile this?

~~~
Aldo_MX
What if you need a job because your company decided to do a massive layoff?

Usually I would have fun at dumb recruiting processes, but right now I'm in no
condition to be picky about getting a new job.

------
sago
How about storing the structures in linked lists, and printing them
recursively?

------
zamalek
Cute, but it probably wouldn't make it past the HR filter.

~~~
eps
That in itself is a good selector for companies where HR wields more power
than the engineering.

------
skrowl
I bet HR people will love this

------
forrestthewoods
Cute. Effort I'm willing to spend parsing a resume: zero. Not sure if this is
a net win or not.

------
raverbashing
> thing_t * thing

This makes my head hurt!

I'd prefer thing_t *thing.

But it's a nice concept

~~~
masklinn
Surely it should be `thing_t* thing`!

~~~
malka
thing_t* thing_ptr, thing

imo, the star should be with the variable name. because, in this case, a
reader could think that both thing_ptr and thing are pointer to a thing_t

"thing_t _thing_ptr, thing,_ other_thing_ptr" is imo more readable

~~~
perdunov
If one uses the entity* notation, they must always declare each variable with
a separate declaration, that is:

    
    
      thing_t* ptr1;
      thing_t* ptr2;
    

not

    
    
      thing_t* ptr1, ptr2 /* <= oops */;

------
veihan
This could be good idea, if it would lead to omission those retarded
screenings.

