Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C源代码中使用basename()和dirname()的GNU版本_C_Posix_Gnu_Dirname - Fatal编程技术网

在C源代码中使用basename()和dirname()的GNU版本

在C源代码中使用basename()和dirname()的GNU版本,c,posix,gnu,dirname,C,Posix,Gnu,Dirname,如何使用GNU C库版本的basename()和dirname() 如果你 #include <libgen.h> 据我所知,C中没有条件导入。是否有特定于gcc的技巧?确保您使用的是GNU C库,而不是系统(假定)的POSIX兼容默认库 这通常在GCC规范文件中设置。使用-v选项显示当前设置: $ gcc -v Using built-in specs. Target: x86_64-linux-gnu Configured with: ../src/configure -v -

如何使用GNU C库版本的
basename()
dirname()

如果你

#include <libgen.h>

据我所知,C中没有条件导入。是否有特定于gcc的技巧?

确保您使用的是GNU C库,而不是系统(假定)的POSIX兼容默认库

这通常在GCC规范文件中设置。使用-v选项显示当前设置:

$ gcc -v
Using built-in specs.
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.4.4-14ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.4 --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5)

根据手册页,您应该这样做

      #define _GNU_SOURCE
       #include <string.h>
       #include <libgen.h>

只需自己编写,并给它一个不同于
basename
的名称。GNU坚持创建可以用1-3行编写的标准函数的替代不一致版本,这是完全愚蠢的

char *gnu_basename(char *path)
{
    char *base = strrchr(path, '/');
    return base ? base+1 : path;
}

这样,您的程序也将更具可移植性。

在检查了
libgen.h
之后,我确信我有一个无警告、无错误的解决方案:

/* my C program */
#define _GNU_SOURCE     /*  for GNU version of basename(3) */
#include <libgen.h>     /*  for dirname(3) */
#undef basename         /*  (snide comment about libgen.h removed) */
#include <string.h>     /*  for basename(3) (GNU version) and strcmp(3) */

/* rest of C program... */
/*我的C程序*/
#为basename的GNU版本定义_GNU_SOURCE/*(3)*/
#包括/*用于目录名(3)*/
#undef basename/*(删除了关于libgen.h的snide注释)*/
#包括/*用于basename(3)(GNU版本)和strcmp(3)*/
/*C程序的其余部分*/
使用
#undef
行,现在我的程序包括
libgen.h
中的
dirname(3)
string.h
中的
basename(3)
的GNU版本


没有来自
gcc
(版本4.5.2)或
clang
(版本3.3)的编译器警告/错误。

很疯狂,basename和dirname有两个版本

我们在一个大项目中工作,看起来这两个API已经导致了 潜在的bug。因此,我们将“basename”“dirname”标记为已弃用,以警告 有人使用它:

#ifdef basename
__attribute__ ((deprecated))
char *__xpg_basename(char *path);
#else
__attribute__ ((deprecated))
char *basename(const char *path);
#endif

 __attribute__ ((deprecated))
char *dirname(char *path);

我们还介绍了一个C语言基础库,比如GLIB或LICORK, 但是看起来太重了。因此,我们为此编写了一个小型库 实施方式如下:

#include <libgen.h>       // for dirname
#include <linux/limits.h> // for PATH_MAX
#include <stdio.h>        // for snprintf
#include <string.h>       // for basename
#include <stdbool.h>      // for bool

bool get_basename(const char *path, char *name, size_t name_size) {
  char path_copy[PATH_MAX] = {'\0'};
  strncpy(path_copy, path, sizeof(path_copy) - 1);
  return snprintf(name, name_size, "%s", basename(path_copy)) < name_size;
}

bool get_dirname(const char *path, char *name, size_t name_size) {
  char path_copy[PATH_MAX] = {'\0'};
  strncpy(path_copy, path, sizeof(path_copy) - 1);
  return snprintf(name, name_size, "%s", dirname(path_copy)) < name_size;
}
#包含//用于目录名
#包括//用于路径_MAX
#包括//用于snprintf
#包含//作为basename
#包括//for bool
bool get_basename(常量字符*路径、字符*名称、大小\u t名称\u大小){
char path_copy[path_MAX]={'\0'};
strncpy(path\u copy,path,sizeof(path\u copy)-1);
返回snprintf(名称、名称大小、%s)、basename(路径副本))

然后我们将所有
basename
dirname
调用替换为
get\u basename
get\u dirname

basename替换为dirname
对我来说毫无意义简单化更具体的回答3行给了我u xpg\u basename@@GLIBC\u 2.0,没有libgen给我basename@@GLIBC\u 2.0(nm提供)。不定义GNU所以URCE给了我basename@@@GLIBC_2.0,但警告初始化使指针从整数变为无castI think-D_GNU_SOURCE与定义_GNU_SOURCE的作用相同,如果我同时定义两个,它会发出警告。@Roman:-D_GNU__SOURCE的作用相同,但时间不同。这正是我所说的区别。指针转换警告,就是指针转换警告。您可以通过提供所需的参数类型来解决此问题。您的普通实现将在“/”和“/home/mine/”方面出现问题。这是为函数的GNU版本指定的行为!请参阅“GNU版本从不修改其参数,并且在路径有尾随斜杠时返回空字符串,尤其是在路径为“/”时。”如果您不希望出现损坏的GNU行为,请不要要求它…好的-最好有一个好的理由让GNU自行运行。我要记下这个特点。我赞同“不修改论点”。我有自己的带前缀的版本,它有一个大小的缓冲区来复制basename,并且它有一个
const char*
参数作为输入。对于这样的函数,用您期望的确切语义编写自己的函数才是最有意义的。@Jonathan Leffler如果我误解了,请原谅我,但我认为Roman在问如何确保使用这些函数的GNU版本。我遇到了一个类似的问题——尽管没有包括libgen.h,但路径正在被修改。作为R。。前面提到过,编写自己的代码很简单,但是我不明白如果GNU版本满足我的需要,为什么我要这么做?
#ifdef basename
__attribute__ ((deprecated))
char *__xpg_basename(char *path);
#else
__attribute__ ((deprecated))
char *basename(const char *path);
#endif

 __attribute__ ((deprecated))
char *dirname(char *path);
#include <libgen.h>       // for dirname
#include <linux/limits.h> // for PATH_MAX
#include <stdio.h>        // for snprintf
#include <string.h>       // for basename
#include <stdbool.h>      // for bool

bool get_basename(const char *path, char *name, size_t name_size) {
  char path_copy[PATH_MAX] = {'\0'};
  strncpy(path_copy, path, sizeof(path_copy) - 1);
  return snprintf(name, name_size, "%s", basename(path_copy)) < name_size;
}

bool get_dirname(const char *path, char *name, size_t name_size) {
  char path_copy[PATH_MAX] = {'\0'};
  strncpy(path_copy, path, sizeof(path_copy) - 1);
  return snprintf(name, name_size, "%s", dirname(path_copy)) < name_size;
}