简体   繁体   English

使用写入 function 重新编码 printf %p,没有 printf

[英]Recoding printf %p with write function, no printf

I am currently working on a task where I need to print the address of a variable.我目前正在处理需要打印变量地址的任务。 It would be easy to use printf %p but I am only allowed to use write from unistd.使用 printf %p 很容易,但我只能使用 unistd 的写入。

I tried casting the pointer in to an unsigned integer and uintptr_t and then converting it into a hexadecimal number.我尝试将指针转换为无符号 integer 和 uintptr_t,然后将其转换为十六进制数。 With uintptr_t it works but with an unsigned integer it only prints half of the address.使用 uintptr_t 它可以工作,但使用无符号 integer 它只打印地址的一半。 Maybe someone can explain me why this is the case?也许有人可以解释我为什么会这样?

I also saw some solutions using ">>" and "<<" but I didn't get why that works.我还看到了一些使用“>>”和“<<”的解决方案,但我不明白为什么会这样。 It would be nice if someone can explain a solution using "<<" and ">>" step by step, because I am not sure if I am allowed to use uintptr_t.如果有人可以逐步解释使用“<<”和“>>”的解决方案,那就太好了,因为我不确定是否允许我使用 uintptr_t。

this is the code I use to cast it into a unsigned int / unitptr_t / unsigned long long (I know that ft_rec_hex is missing leading 0's):这是我用来将其转换为 unsigned int / unitptr_t / unsigned long long 的代码(我知道 ft_rec_hex 缺少前导 0):

void ft_rec_hex(unsigned long long nbr)
{
    char tmp;

    if (nbr != 0)
    {
        ft_rec_hex(nbr / 16);
        if (nbr % 16 < 10)
            tmp = nbr % 16 + '0';
        else
            tmp = (nbr % 16) - 10 + 'a';
        write(1, &tmp, 1);
    }
}

int     main(void)
{
    char c = 'd';
    unsigned  long long ui = (unsigned long long)&c;
    ft_rec_hex(ui);
}

It looks like only half of the address is printed because the "unsigned integer" you used has only half size of uintptr_t .看起来只打印了一半的地址,因为您使用的“无符号整数”只有uintptr_t的一半大小。 (note that uintptr_t is an unsigned integer type) (注意uintptr_t是无符号 integer 类型)

You can use an array of unsigned char to store data in a pointer variable and print that to print full pointer withput uintptr_t .您可以使用unsigned char数组将数据存储在指针变量中并打印它以使用put uintptr_t打印完整指针。

Using character types to read objects with other type is allowed according to strict aliasing rule .根据严格的别名规则,允许使用字符类型读取其他类型的对象。

#include <stdio.h>
#include <unistd.h>

void printOne(unsigned char v) {
    const char* chars = "0123456789ABCDEF";
    char data[2];
    data[0] = chars[(v >> 4) & 0xf];
    data[1] = chars[v & 0xf];
    write(1, data, 2);
}

int main(void) {
    int a;
    int* p = &a;
    /* to make sure the value is correct */
    printf("p = %p\n", (void*)p);
    fflush(stdout);

    unsigned char ptrData[sizeof(int*)];
    for(size_t i = 0; i < sizeof(int*); i++) {
        ptrData[i] = ((unsigned char*)&p)[i];
    }
    /* print in reversed order, assuming little endian */
    for (size_t i = sizeof(int*); i > 0; i--) {
        printOne(ptrData[i - 1]);
    }

    return 0;
}

Or read data in a pointer variable as unsigned char array without copying:或者将指针变量中的数据作为unsigned char数组读取而不复制:

#include <stdio.h>
#include <unistd.h>

void printOne(unsigned char v) {
    const char* chars = "0123456789ABCDEF";
    char data[2];
    data[0] = chars[(v >> 4) & 0xf];
    data[1] = chars[v & 0xf];
    write(1, data, 2);
}

int main(void) {
    int a;
    int* p = &a;
    /* to make sure the value is correct */
    printf("p = %p\n", (void*)p);
    fflush(stdout);

    /* print in reversed order, assuming little endian */
    for (size_t i = sizeof(int*); i > 0; i--) {
        printOne(((unsigned char*)&p)[i - 1]);
    }

    return 0;
}

It would be easy to use printf %p but I am only allowed to use write from unistd.使用 printf %p 很容易,但我只能使用 unistd 的写入。

Then form a string and print that.然后形成一个字符串并打印出来。

int n = snprintf(NULL, 0, "%p", (void *) p);
char buf[n+1];
snprintf(buf, sizeof buf, "%p", (void *) p);
write(1, buf, n);

Using a pointer converted to an integer marginally reduces portability and does not certainly form the best textual representation of the pointer - something implementation dependent.使用转换为 integer 的指针会略微降低可移植性,并且肯定不会形成指针的最佳文本表示 - 这取决于实现。


With uintptr_t it works but with an unsigned integer it only prints half of the address.使用 uintptr_t 它可以工作,但使用无符号 integer 它只打印地址的一半。

unsigned is not specified to be wide enough to contain all the information in a pointer. unsigned未指定为足够宽以包含指针中的所有信息。

uintptr_t , when available (very common), can preserve most of that information for void pointers. uintptr_t在可用时(非常常见)可以为void指针保留大部分信息。 Good enough to round-trip to an equivalent pointer, even if in another form.足以往返到等效指针,即使是另一种形式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM