指针的值未被修改
最近,为了一个小项目,我需要为pwd.h写一个极简替代实现;然而,在实现一个函数时,似乎有些地方不对劲。win_pwd.h的代码是:
#ifndef _PWD_H
#define _PWD_H 1
#include <stdlib.h>
#include <stddef.h>
typedef unsigned int uid_t;
typedef unsigned int gid_t;
struct passwd{
char * pw_name; // User Log-in Name
uid_t pw_uid; // Numerical User ID
gid_t pw_gid; // Numerical Group ID
char * pw_dir; // Initial Working Directory
char * pw_shell; // Program to use as a shell
};
int getpwnam_r(const char * name, struct passwd * pwd,
char * buffer, size_t size, struct passwd ** result){
*result = malloc(sizeof(struct passwd));
(* result )->pw_name = getenv("USERNAME");
(* result )->pw_dir = getenv("PWD");
(* result )->pw_shell = "powershell.exe";
(* result )->pw_uid = 1;
(* result )->pw_gid = 1;
pwd = * result;
result[0] = NULL;
return 0;
}
#endif
而main.c的代码是:
#include "win_pwd.h"
#include <stdio.h>
int main(){
struct passwd pwent;
struct passwd *pwentp;
char buf[1024];
const char * login = "TEST";
int lol = getpwnam_r(login, &pwent, buf, sizeof buf, &pwentp);
printf("Username: %s\n", pwent.pw_name);
printf("SHELL: %s\n", pwent.pw_shell);
return 0;
}
我本以为代码会把用户名放在pwent.pw_name字段,把pwent.pw_shell字段设为powershell.exe,但两者都是空的,这让我怀疑问题出在返回了未初始化的变量。使用gdb,我发现到了getpwnam_r函数结束时,pwd的内存地址与result[0] 相同;但等到进入Username的 printf语句时,pwent的内存地址又与函数运行前一样。老实说,我已经好几年没用C 编程了,但我一直以为内存地址会这样被修改。我不太清楚我的错在哪里,若能得到帮助,我将不胜感激。
解决方案
你已经得到一个答案,指出你在按当前思路实现该函数时的错误所在。这一部分主要是关于改变这个思路。
c int getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result);The
getpwnam_r()function shall update the passwd structure pointed to bypwdand store a pointer to that structure at the location pointed to byresult. The structure shall contain an entry from the user database with a matching name. Storage referenced by the structure is allocated from the memory provided with thebufferparameter, which isbufsizebytes in size. A null pointer shall be returned at the location pointed to byresulton error or if the requested entry is not found.
So, if you want to mimic the real thing, getpwnam_r should not allocate memory. It should use the memory provided to it.
It could look like this:
// a helper function to append to buffer
static char* add_to_buf(char* buffer, size_t size, size_t* offset,
const char* str) {
char* wr = buffer + *offset;
*offset += snprintf(wr, size - *offset, "%s", str) + 1;
// return pointer to beginning of the new string if it fit in the
// remaining buffer
return *offset < size ? wr : NULL;
}
int getpwnam_r(const char* name, struct passwd* pwd, char* buffer, size_t size,
struct passwd** result) {
*result = NULL;
// lookup `name`, simulated:
const char* USER = getenv("USERNAME");
const char* PWD = getenv("PWD");
// check that the user is found. note: not found is not an error
// so return 0:
if (!USER || !PWD) return 0;
pwd->pw_uid = 1;
pwd->pw_gid = 1;
// fill buffer with the found user information:
size_t offset = 0;
// return ERANGE if the information does not fit in buffer:
if (!(pwd->pw_name = add_to_buf(buffer, size, &offset, USER)))
return ERANGE;
if (!(pwd->pw_dir = add_to_buf(buffer, size, &offset, PWD)))
return ERANGE;
if (!(pwd->pw_shell = add_to_buf(buffer, size, &offset, "powershell.exe")))
return ERANGE;
// success
*result = pwd;
return 0;
}