使用%d vs%ld,linux打印pid

Ada*_*dam 1 c linux printf casting

我在一个pids数组中存储了一系列s(即Linux进程ID)long.我意识到a pid不是a long,但我在使用不同的变量类型方面别无选择.

当我尝试打印pid使用时,我遇到了这个问题printf.如果我打印long存储pid使用的%ld,我得到错误的pids:

8435315771308 process_ancesto
8358006359962 bash
8353711392665 login
4294967297 init
0 swapper/0
Run Code Online (Sandbox Code Playgroud)

但是,如果我使用打印%d(生成编译器警告),我会得到正确的结果(即通过键入ps终端返回的结果):

1969 process_ancesto
1946 bash
1945 login
1 init
0 swapper/0
Run Code Online (Sandbox Code Playgroud)

是什么导致了这种行为?pid - > long cast是一个扩大的转换,不应该导致任何问题.

这是我用来进行系统调用的程序,它返回pids:

int main(int argc, char *argv[])
{
    struct process_info arr[10];
    long n=0;
    int result = syscall(_CS300_PROCESS_ANCESTORS_, arr,10,&n);
    assert(result==0);
    for(int i=0;i<n;i++) {
        printf("%d %s\n",arr[i].pid,arr[i].name);
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果我更换%d%ld它打印不正确的信息.

这是我系统调用的行,我记录了pid:

if(copy_long_to_user(&info_array[num_filled_kernel].pid, &curr_task->pid)) {                
            return -EFAULT;
        }
Run Code Online (Sandbox Code Playgroud)

info_array[num_filled_kernel].pid 很久了.

Nat*_*dge 5

两个问题:

在你的copy_to_user,第二个参数是一个指针pid_t,它出现,如你所说是一个int(32位).所以你从32位变量复制64位; 如果幸运的话,其余的32位(高半部分,因为x86是小端)将填充内存中的下一个内容.(如果你运气不好,你会在这里遇到错误.)当你通过指针访问事物时,不会进行整数转换.

安全地执行此操作的最简单方法是使用临时变量:

long tmp = curr_task->pid; // sign-extension done here
copy_long_to_user(..., &tmp);
Run Code Online (Sandbox Code Playgroud)

然后在您的用户空间代码中,您使用%d格式说明符来打印显然是的东西long.这不起作用; printf作为一个可变函数,它不知道它的参数预期具有的类型,因此不能适当地转换它们.如果您要传递a long,请使用%ld格式说明符.