67

My code is:

#include <stdio.h>
#include <string.h>

void main()
    {
    char string[10];
    int A = -73;
    unsigned int B = 31337;

    strcpy(string, "sample");

    // printing with different formats
    printf("[A] Dec: %d, Hex: %x, Unsigned: %u\n", A,A,A);
    printf("[B] Dec: %d, Hex: %x, Unsigned: %u\n", B,B,B);
    printf("[field width on B] 3: '%3u', 10: '%10u', '%08u'\n", B,B,B);

    // Example of unary address operator (dereferencing) and a %x
    // format string 
    printf("variable A is at address: %08x\n", &A);

I am using the terminal in linux mint to compile, and when I try to compile using gcc I get the following error message:

basicStringFormatting.c: In function ‘main’:
basicStringFormatting.c:18:2: warning: format ‘%x’ expects argument
of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("variable A is at address: %08x\n", &A);

All I am trying to do is print the address in memory of the variable A.

P.P
  • 117,907
  • 20
  • 175
  • 238
varlotbarnacle
  • 821
  • 1
  • 6
  • 7
  • 19
    `void main()` should be `int main(void)`. If your book, tutorial, or instructor told you to use `void main()`, find a better one. – Keith Thompson May 20 '15 at 15:34
  • 2
    @KeithThompson How does that matter? – Prakhar Agrawal Mar 16 '17 at 16:45
  • 5
    @PrakharAgrawal: It matters because the 1989 ANSI C standard, which introduced the `void` keyword, also specified that the main function may be defined as `int main(void) { /* ... */ }`. It says nothing about `void main()`, and a conforming implementation may reject it. There are plenty of books and tutorials that suggest using `void main()`; this is a strong indication that the author really doesn't know the language very well. (This is for hosted implementations. For freestanding implementations, where the program doesn't run under an OS, the program entry point is implementation-defined. – Keith Thompson Mar 16 '17 at 19:03
  • 3
    @PrakharAgrawal: See also the [comp.lang.c FAQ](http://www.c-faq.com/), starting with question 11.12a. – Keith Thompson Mar 16 '17 at 19:04
  • @KeithThompson Thanks! – Prakhar Agrawal Mar 17 '17 at 06:01
  • 1
    Possible duplicate of [Correct format specifier to print pointer (address)?](https://stackoverflow.com/questions/9053658/correct-format-specifier-to-print-pointer-address) – phuclv Sep 13 '17 at 03:53

2 Answers2

127

Use the format specifier %p:

printf("variable A is at address: %p\n", (void*)&A);

The standard requires that the argument is of type void* for %p specifier. Since, printf is a variadic function, there's no implicit conversion to void * from T * which would happen implicitly for any non-variadic functions in C. Hence, the cast is required. To quote the standard:

7.21.6 Formatted input/output functions (C11 draft)

p The argument shall be a pointer to void. The value of the pointer is converted to a sequence of printing characters, in an implementation-defined manner.

Whereas you are using %x, which expects unsigned int whereas &A is of type int *. You can read about format specifiers for printf from the manual. Format specifier mismatch in printf leads to undefined behaviour.

P.P
  • 117,907
  • 20
  • 175
  • 238
  • 12
    Important thing to cast to `void *` – Iharob Al Asimi May 20 '15 at 15:32
  • @Blue Moon - why is it important to cast (void *) ? – ryyker May 20 '15 at 15:39
  • 2
    I tested, in a little app, printing address of variable with and without cast but got same result. But clearly the standard's statement ( _p The argument shall be a pointer to void_ ) leaves little room for interpretation. Thank you. – ryyker May 20 '15 at 16:04
  • So can all pointers convert to `void *`? I _think_ the answer is yes, except maybe not function pointers. – chux - Reinstate Monica May 20 '15 at 16:59
  • Yes, the any object pointer T * can be converted to void * safely and back: **C11 draft, 6.3.2.3, 1 pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again**. But not function pointers: **6.3.2.3, 8 A pointer to a function of one type may be converted to a pointer to a function of another type and back again**. – P.P May 20 '15 at 18:01
  • @Blue Moon This does leave the issue of how to print a function pointer (OP's potential memory address). Cast to `uintmax_t` and hope for the best? – chux - Reinstate Monica May 20 '15 at 18:38
  • 1
    @chux There's no standard way to print a function pointer's address. Casting to `void *` and printing with `%p` or as you say can cast to `uintmax_t` and printing *may* work in practice. But there's no such guarantee it'll work (neither is it standard conforming). The standard leaves the representation of the function pointers to as *implementation defined* and there's no guarantee that the function pointer value is some kind of integer. So casting to any integer type may not work. – P.P May 20 '15 at 18:45
  • @Blue Moon C11 draft informative _J.5.7 Function pointer casts_ implies that casting to `void *` is a usual extension method to print the function pointer - though not guaranteed to be portable. – chux - Reinstate Monica May 20 '15 at 18:53
-2

A workaround to use %x with length specifier to print an int or unsigned int without compiler complaining about casting would be to use malloc:

unsigned int* D = malloc(sizeof(unsigned int)); // Allocates D
unsigned int D_address = *((unsigned int*) &D); // D address for %08x without warning
*D = 75; // D value
printf("variable D is at address: %p / 0x%08x with value: %u\n", D, D_address, *D);

Alternatively you can compile with gcc -w flag to suppress those casting warnings.

Edit for 64-bit addresses:

unsigned long* D = malloc(sizeof(unsigned long)); // Allocates D
unsigned long D_address = *((unsigned long*) &D); // D address for %016lx without warning
*D = ULONG_MAX; // D value
printf("variable D is at address: %p / 0x%016lx with value: %lu\n", D, D_address, *D);
hmofrad
  • 1,784
  • 2
  • 22
  • 28