Hacker News new | past | comments | ask | show | jobs | submit login
C Puzzles (gowrikumar.com)
101 points by brown-dragon on June 23, 2015 | hide | past | favorite | 24 comments



> Write a C program which prints Hello World! without using a semicolon

Here's one way, cheating a bit by abusing the definition of "a C program which prints":

    /tmp$ gcc hw.c
    hw.c:1:2: warning: #warning Hello world! [-Wcpp]
     #warning Hello world!
A more serious solution, though:

    /tmp$ cat hw.c
    #include <stdio.h>
    void main(void)
    {
        if (puts("Hello world!")) {}
    }
    /tmp$ gcc hw.c
    /tmp$ ./a.out
    Hello world!


How about this one? It's not standards-compliant, but GCC swallows it even with -Wall (or at least it used to), and it's by far my favourite:

    int main(int args, char *argv[printf("Hello, world!")]) { }


Nice one but:

>It's not standards-compliant

Why? It's just a VLA.


Per 5.1.2.2.1 [C11 Final Draft], the `main` function should be declared as either

    int main(void) { /* ... */ }
or

    int main(int argc, char *argv[]) { /* ... */ }


You missed the relevant text:

>or equivalent; 10)

>10) Thus, int can be replaced by a typedef name defined as int, or the type of argv can be written as char * * argv, and so on.

And Standard also says that:

>or in some other implementation-defined manner.

and:

>In a freestanding environment (in which C program execution may take place without any benefit of an operating system), the name and type of the function called at program startup are implementation-defined.

So main can be pretty much anything according to the Standard, depending on the system.


    #include <stdio.h>
    int main()
    {
     float a = 12.5;
     printf("%d\n", a);
     printf("%d\n", *(int *)&a);
     return 0;
    }
This program invokes undefined behaviour when it casts float\* to int\*, so technically it could print anything, or do something else. I'm not sure how using memcpy instead would impact the puzzle's point though.


If you know that sizeof(float) >= sizeof(int) the memory alignment should be fine. Also in this case * (int* )&a does not access any bytes outside of an defined data object.

To predict the outcome one have to know the representation of float (IEEE 754) and the big/little endian issues which could be different between floats and ints.

printf("%d\n", a) does promote the value a to a double first (promotion rules) and then either the first or last part i(assuming sizeof(double) == 2*sizeof(int)) is shown depending on little or big endian architecture.


You don't know C.

Reinterpreting an object as an incompatible object is undefined. int and float are incompatible.

C Standard also specifically states that using an incorrect printf format specifier will result in undefined behavior.


I have experimented with printf("%d\n", a); using gcc. When compiled for 32-bit x86, it displays the lower 32 bits of the double (which for 12.5 happen to be all 0).

On x86-64, it displays a random value each time, which actually happens to be some pointer (randomised by ASLR). This is because register passing is used on x86-64, and the the double is stored into a floating point register, but %d reads from a different register.

printf("%d\n", * (int*)&a); produces the number 1095237632 for both x86 and x86-64.


Technically, it will print the first N bytes of the float as an int. Where N is the number of bytes ints compile to on the platform. So with knowledge of the platform, the result is entirely predictable.


Only with knowledge of platform AND compiler, though.

Also these are C puzzles and casting pointers to incompatible types and dereferencing them is undefined behavior. Using memcpy would indeed fix this according to e.g. [1].

[1] http://blog.llvm.org/2011/05/what-every-c-programmer-should-... (section "Violating Type Rules")


UB according to the standard has no restrictions, but I think the point of these puzzles is to explain what could reasonably happen on a typical system, and why.


Actually it invokes undefined behavior when it passes a float to printf() and then tries to print it using %d (which of course expects int). Don't do that.


One of these reminded me of my woeful attempts at IOCCC-like code, a Hello World implementation:

http://students.mimuw.edu.pl/~dj189395/nhp/czynic/programy/t...


That was fun to read. Why do you need a terminating null (juz)?


It isn't actually used in printf; there's one more argument than there are %c specifiers. gcc -Wall warns about that.


Good catch! And even if we do add another "%c" to fix it, I don't know why we would need to null-terminate a null-terminated string.


If you added another %c, it would print the NUL to stdout; it doesn't terminate anything.


You're right. My mistake.


Anyone else spot the uninitialized variable in the banner program?

Also:

> What's the output of the following program. (No, it's not 10!!!)

What's the point of including a program that calls malloc without including a prototype for it, after asking the reader earlier answer why such a program segfaults on IA-64 but not IA-32?

(The answer is: a constraint is violated, requiring a diagnostic, because an int * object pointer is assigned the return value of malloc whose implicit declaration marks it as returning int. The comment issue is a red herring.)


I can't figure out why is it checking `pr` in the while loop. Perhaps it's simply been left over from an earlier version.


That's funny, I added the include for stdlib so couldn't find the issue with the malloc one.


I couldn't find the book at the hint provided... Could someone help me get that book. Thanks in advance


You can get a copy here: http://www.amazon.com/dp/0131103628




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: