Строковый формат для intptr_t и uintptr_t

Что такое строковый формат для intptr_t и uintptr_t, который действителен для 32-разрядной и 64-битной архитектуры.

ИЗМЕНИТЬ

warning: format ‘%x’ expects type ‘unsigned int’, but argument 2 has type "AAA"

Это предупреждение, которое я получаю в 64 бит, но не в 32 бит.

  intptr_t  AAA

Ответ 1

Это будут следующие макросы из inttypes.h:

Для printf: PRIdPTR PRIiPTR PRIoPTR PRIuPTR PRIxPTR PRIXPTR

Для scanf: SCNdPTR SCNiPTR SCNoPTR SCNuPTR SCNxPTR

Пример использования:

uintptr_t p = SOME_VALUE;
printf("Here a pointer for you: %" PRIxPTR "\n", p);

Ответ 2

Я думаю, вы должны рассмотреть возможность использования модификатора 'Z'. Это преобразует все, что соответствует size_t или ssize_t, и я обнаружил, что это работает и с (u) intptr_t.

Например:

intptr_t ip =...; printf ("ip =% zd\n", ip);

Ответ 3

Я думаю, что даже long int небезопасно, и вы должны попробовать long long int, который должен существовать, потому что вы работаете с 64-битной архитектурой, и у вас уже есть intptr_t.

В некоторых 64-разрядных архитектурах (я думаю, Microsoft Windows будет такой), long int может храниться в 32-битной ширине, чтобы удовлетворить предположению MS-DOS-age, что short int всегда 16-бит и long int всегда 32-разрядный.

Даже на тех платформах с 32-разрядным long int, printf("%llx", (unsigned long long)AAA); будет работать. И вы должны рассмотреть более предпочтительную форму printf("%jx", (uintmax_t)AAA);, если это возможно.

Обратите внимание, что для некоторых старых компиляторов вам может понадобиться использовать "%Lx" (для GNU C с литьем в unsigned long long) или "%I64x" (для Visual С++ с отливкой до __uint64) для 64-битных целых чисел.

Р. С. %p может быть не очень хорошим в этом случае, потому что %p может печатать bareword 0x перед шестнадцатеричными элементами и/или может печатать нулевое значение. Если оба применяются, например, код printf("%p\n", (void*)16); будет печатать 0x00000010 на 32-битных платформах и 0x0000000000000010 на 64-битных платформах; плакат должен надеяться, что будет напечатан только 10.

Ответ 4

%p должен работать как замена для %x, так как uintptr_t определяется как целое число без знака с тем же размером, что и указатель на платформе.

EDIT: К сожалению, по крайней мере, на моем компиляторе вам нужно передать переменную в (void *). Тем не менее, я думаю, что безопасно отображать uintptr_t указателю.

Ответ 5

Я компилирую некоторый код в среде, которая по какой-то причине не имеет макросов PRI.PTR, определенных в inttypes.h, и в которых intptr_t определяется как int в 32 бит и long int в 64 бит.

Я взломал предупреждения, используя спецификатор формата %li и перебросив переменные в long int в параметрах printf. Это безопасно в этой среде, поскольку intptr_t никогда не может быть длиннее long int, как описано выше.

Я бы не рекомендовал использовать это решение, если вы можете его избежать, но он решил, по крайней мере, предупреждения.

Ответ 6

####################################### CPP type proving code (identifying type by typeid)
$ cat typeid.cpp
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <time.h>
#include <typeinfo>

#define name(t) printf("%30s : %s\n", #t, typeid(t).name())

// g++|clang++ -o ./typeid.exe typeid.cpp -m32 && ./typeid.exe
// g++|clang++ -o ./typeid.exe typeid.cpp -m64 && ./typeid.exe
int main(int argc, char* argv[]) {
    name(ptrdiff_t);
    name(intptr_t);
    name(uintptr_t);

    return 0;
}

####################################### C type proving code (identifying type by _Generic)
$ cat typeid.c 
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <time.h>

/* matches the type name of an expression */
#define name_match(e) _Generic((e), \
                 _Bool: "_Bool", \
                  char: "char", \
           signed char: "signed char", \
         unsigned char: "unsigned char", \
                 short: "short", \
        unsigned short: "unsigned short", \
                   int: "int", \
          unsigned int: "unsigned int", \
                  long: "long", \
         unsigned long: "unsigned long", \
             long long: "long long", \
    unsigned long long: "unsigned long long", \
                 float: "float", \
                double: "double", \
           long double: "long double", \
               default: "unknown")

#define name(t, e) printf("%30s : %s\n", #t, name_match(e))

int main() {
    ptrdiff_t ptrdiff_v = 0;
    intptr_t  intptr_v = 0;
    uintptr_t uintptr_v = 0;

    name(ptrdiff_t, ptrdiff_v);
    name(intptr_t,  intptr_v);
    name(uintptr_t, uintptr_v);
}

####################################### run in arch32
$ clang++ -o ./typeid.exe typeid.cpp -m32 && ./typeid.exe
                     ptrdiff_t : i
                      intptr_t : i
                     uintptr_t : j

$ clang -o ./typeid.exe typeid.c -m32 && ./typeid.exe      
                     ptrdiff_t : int
                      intptr_t : int
                     uintptr_t : unsigned int
result:
     intptr_t == ptrdiff_t
    uintptr_t == unsigned ptrdiff_t

####################################### run in arch64
$ clang++ -o ./typeid.exe typeid.cpp -m64 && ./typeid.exe
                     ptrdiff_t : l
                      intptr_t : l
                     uintptr_t : m

$ clang -o ./typeid.exe typeid.c -m64 && ./typeid.exe   
                     ptrdiff_t : long
                      intptr_t : long
                     uintptr_t : unsigned long
result:
     intptr_t == ptrdiff_t
    uintptr_t == unsigned ptrdiff_t

####################################### man 3 printf
t -- A following integer conversion corresponds to a ptrdiff_t argument.

####################################### conclusion
//  intptr_t == ptrdiff_t
// uintptr_t == unsigned ptrdiff_t
// so:
//     1)  intptr_t has string format %td
//     2) uintptr_t has string format %tu

#include <stdio.h>
#include <stdint.h>

int main(int argc, char *argv[]) {
    intptr_t  x = 0;
    uintptr_t y = 0;

    scanf("%td %tu", &x, &y);
    printf("out: %td %tu\n", x, y);
    return 0;
}