0

I'm a newbie to C programming and I've found this strange behaviour while using the following placeholders specification in the function printf's argument. I get two different results while using an online C compiler (OnlineGDB) and VSCode with gcc terminal compilation. That's the snippet:

#include <stdio.h>

int main()
{
    printf("%lld", 4);
    return 0;
}

As Wiki says, "the ll lenght field placeholder is made for integer types, and causes printf to expect a long long-sized integer argument". In the online Compiler I get this:

main.c:13:16: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 2 has type ‘int’ [-Wformat= ]
4

So it prints 4 after a warning.

The result in VSCode is completely different :

15621861207441412

No warnings but where's that number coming from?

Why is there such a different behaviour in such a "simple" situation? Isn't the value 4 also an ll-integer? My guess is that the second one expects a bigger value so it sends me a quite a random value in that interval. Also, I have to study C for a college exam, could you recommend which compiler should I use in compiling sample projects? Thanks a lot for you time.

  • 1
    The warning is correct. `4` is an `int` literal. To have a `long long` literal, you need to write `4LL`, as you have said. Also, which compiler are you using in VSCode, MSVC? Have you tried enabling all warnings in that? I haven't used MSVC, but it should give a warning if you do that. Your online compiler is probably using either GCC or clang. – mediocrevegetable1 Apr 02 '21 at 09:08
  • A compiler isn't obliged to warn about arguments for variadic functions. By nature their use is unknown by the compiler but in the case of `printf` a helpful compiler analyses the format string and checks the arguments are the right type. MSVC does this for `printf()` and `fprintf()` and `sprintf()` but not its own `cprintf()` function. Note that `4` is by default an `int` type, try `4LL`. – Weather Vane Apr 02 '21 at 09:16
  • https://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior – M.M Apr 02 '21 at 09:23
  • The `printf()` function *trusts* that you have placed the data matching the format specifications on the stack. If the format requires 8 bytes, then 8 bytes are used regardless of *why* they are on the stack. In one of your environments the other 4 bytes happened to be 0. – Weather Vane Apr 02 '21 at 09:25
  • 1
    @mediocrevegetable1 Detail: C specifies `4` as a _constant_, not a _literal_. C specifies 2 literals: _string_ and _compound_. These literals can have their address taken, unlike a constant. Good point about warnings. – chux - Reinstate Monica Apr 02 '21 at 10:14
  • @chux-ReinstateMonica Interesting, I hadn't realized that. I generally use literal and constant interchangeably (apart from with string and compound literal), so thanks for correcting me on that, I'll keep that in mind. – mediocrevegetable1 Apr 02 '21 at 10:18

1 Answers1

3

Note that doing printf("%lld", 4); is undefined behavior and I totally believe your code should spawn demons. Do not write code with undefined behavior - only write code you know how it will behave.

but where's that number coming from?

Imagine your platform is little endian, int has 4 bytes and long long has 8 bytes (and byte has 8 bits). So... %lld reads 64-bits. But 4 is an int so only 32-bits are required to have value 4, and the other 32-bits are... not touched, left being (compiler makes this decision, compiler may also make the decision to zero them). To visualize, the register/stack with the 4 value may look like this after printf is called:

[0x04][0x00][0x00][0x00][0x??][0x??][0x??][0x??]
                        ^^^^^^^^^^^^^^^^^^^^^^^^  - 32-bits uninitialized
^^^^^^^^^^^^^^^^^^^^^^^                           - 32-bits filled with 4
 compiler initializes only first 4 bytes, does not care about more
            

The uninitialized values are just some leftovers from some previous operation (previous program? C startup routine?). The value 15621861207441412 is equal to 0x0037800000000004 - you may note that that the low-order 8 bytes are 0x00000004, and 0x00378000 is some leftover uninitialized bytes that printf picked up.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • Ty very much for this clarification. I need to study in deep the features of C to better understand what it's happening and why. Any advice on good manuals for this language? The book that my professor suggested seems a bit confusing... – Valerio Giovannini Apr 02 '21 at 10:26
  • Well, C is not assembly. In C, _as a language_, doing `printf("%lld", 4);` is just invalid, it's meaningless. There is [this](https://stackoverflow.com/questions/562303/the-definitive-c-book-guide-and-list), For a _beginner_ C and machine code interaction, I think I could recommend Arduino and some introduction to them. – KamilCuk Apr 02 '21 at 10:46