What is printed by the following C code?

From an exercise in a book, what is printed by the following C code?

#define a (x+1)
int x = 2;
void b() { x = a; printf("%d\n", x); }
void c() { int x = 1; printf("%d\n"), a; }
void main() { b(); c(); }

I dunno but that second printf is missing an argument.

Is this a homework assignment?

1 Like

While I canā€™t guarantee that Bill hasnā€™t gone back to school, Iā€™m pretty sure he isnā€™t trying to cheat on any homework.

4 Likes

2
2

Had to think about that a minute.

And itā€™s been too long since I did C on a regular basisā€¦

Corrected the parenthesis of the second printf()ā€¦
a is just a macro for x+1ā€¦

3
2

1 Like

Ummmm, I think youā€™re missing a bit. My C is rusty at best, itā€™s only been a couple decades since Iā€™ve had to wrestle C code.

We set x to 2, then we set x equal to a, which is x+1 and then print it with a new line. So your first line will be 3.

Depending upon the compiler, you will return an error for c() due to returning something when main is typed void.

Eh, let the roast begin.

This is one of the exercises in the book, but it is not my homework. For light reading, I am going through an updated edition of a compiler book.

2 Likes

Good eye. That was what caught my attention.

The authors meant to test the readersā€™ understanding of variable scoping, but a typo messed up the code.

I think they intended

void c() { int x = 1; printf("%d\n", a); }

Due to properties of the language, it still compiled and may have even given the answer they expected when executed.

3 Likes

b prints 3

c defines a new x inside its scope, but ultimately itā€™s not used.

The comma a part in the c function should do nothing in this case. I didnā€™t even know that was valid syntax. TIL: https://www.geeksforgeeks.org/comna-in-c-and-c/

The printf in C without supplying an argument basically makes its output undefined. From what Iā€™ve read it could cause a crash and someone said ā€œif youā€™re lucky, youā€™ll get a seg faultā€ :slight_smile:

FWIW: This shows 3 and 2^32 - 2 for some reason: https://www.onlinegdb.com/online_c_compiler

A #define in C results in a simple text substitution by the macro processor before the code is compiled. So function b() increments the global x then prints it.

Function c() has its own local instance of x, so that plus one is supposed to be printed. Because a is a macro and not a function, it has no connection to the global x within function c.

The authors intended
3
2

but because of the typo, the code actually prints
3
<whatever happens to be on the stack>

2 Likes

13 years of LabVIEW have made me a bit rusty on C. I forgot how the compiler define worked. I automatically corrected the typo with the argument in the second function though. Local scope still makes sense.

1 Like

void b() should print to stdout the value of 2+1 or 3. (global x ::= 2, global a ::= 2+1, local x ::= 2+1, local print x)

void c() should print 1+1. (global x is not used, local x ::= 1, global a ::= local x +1, local print 2)

so given a good compiler we should get:

ā€˜3\nā€™
ā€˜2\nā€™
exit code 0

scratch that ā€¦ Bill your right. it would print the stack or the compiler would throw a syntax error.

1 Like

Much to many programmersā€™ frustration,

void c() { int x = 1; printf("%d\n"), a; }

is valid C, so a compiler will not flag it as an error.

Well damnā€¦ even gcc accepts it. I wonder llvm or borderland doesā€¦

root@c57f3f88eba0:~# gcc -o fu test.c
root@c57f3f88eba0:~# ./fu
2
-580222960
root@c57f3f88eba0:~# gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/6/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 6.3.0-18+deb9u1' --with-bugurl=file:///usr/share/doc/gcc-6/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-6 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-6-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-6-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-6-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar
--with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 6.3.0 20170516 (Debian 6.3.0-18+deb9u1)
root@c57f3f88eba0:~#

haā€¦ clang / llvm:

root@c57f3f88eba0:~# clang test.c -S -O3 -o fu
test.c:16:12: warning: more '%' conversions than data arguments [-Wformat]
  printf("%d\n"), a;
          ~^
test.c:16:19: warning: expression result unused [-Wunused-value]
  printf("%d\n"), a;
                  ^
test.c:3:14: note: expanded from macro 'a'
#define a (x +1)
           ~ ^~
test.c:19:5: error: second parameter of 'main' (argument array) must be of type 'char **'
int main(int argc, char **argv[]) {
    ^
2 warnings and 1 error generated.
root@c57f3f88eba0:~#

that caught it!

Even without optimisations:

root@c57f3f88eba0:~# clang test.c -o fu
test.c:6:32: warning: more '%' conversions than data arguments [-Wformat]
void c() { int x = 1; printf("%d\n"), a; }
                              ~^
test.c:6:39: warning: expression result unused [-Wunused-value]
void c() { int x = 1; printf("%d\n"), a; }
                                      ^
test.c:3:13: note: expanded from macro 'a'
#define a (x+1)
           ~^~
2 warnings generated.
root@c57f3f88eba0:~#