【问题标题】:C-program on macOS cannot open its input filemacOS 上的 C 程序无法打开其输入文件
【发布时间】:2019-07-07 07:05:57
【问题描述】:

我有一个使用 gcc 和 makefile 在 macOS High Sierra 上构建的 C 程序。程序做的第一件事是读取一个二进制输入文件。文件名可以在终端命令行中与 shell 命令一起指定,也可以在未指定时由程序要求提供。

我的问题是当输入文件没有与shell命令一起指定时,程序返回错误,说它无法打开文件。

以下是有效和无效的方法: (程序和输入文件在同一目录下)

  1. 打开终端
  2. 从命令行输入:

    ./program_name –i input.dat

=> 工作正常

  1. 打开终端
  2. 从命令行类型:

    ./program_name

  3. 程序提示: 输入文件:
  4. 我输入:input.dat

=> 打开文件出错

  1. 打开 Finder 并转到包含程序和输入文件的目录
  2. 双击程序名称图标
  3. 程序在终端启动并提示: 输入文件:
  4. 我输入:input.dat

=> 打开文件出错

我在运行正常的 linux 和 windows 上运行完全相同的源代码,所以我认为它一定是我不理解的操作系统的东西?

我可以补充一点,该程序不受信任,因为它不是来自应用商店。 CTRL-点击图标解决了这个问题。

--EDIT - 很抱歉没有添加可验证的代码。

澄清:argc/argv 部分工作正常。这是例程的最后一部分,它提示输入出错的文件名。也许这确实是 Jabberwocky 建议的路径。我今晚会检查一下,并会在这里跟进。

void GetFileName(nr_args, args, filename, json)
 int  nr_args;
 char **args;
 char *filename;
 int* json;
{
  int i = 1;

  filename[0]  = '\0';

  /* the command 'interpreter' itself is stored in argv[0] */

  while (i<nr_args) {
    if (strcmp(args[i], "-e") == 0) {
  /* we cannot set the json flag here, because */
  /* flags have not been initialized yet       */
  *json = 1;
  i++;
}
else {
  if (strcmp(args[i], "-i") == 0) {
    if (nr_args > i+1) {
      /* inputfile was specified */
      strncpy(filename, args[++i], MAX_ID_LENGTH);
      i++;
        }
      }
      else {
        PrintError(41, NULL, args[i]);
        i++;
      }
    }
  }

  if (filename[0] == '\0') {
    printf("\n\nInputfile: ");
    scanf("%19s", filename);
    filename[MAX_ID_LENGTH] = '\0';
    /* clear the input buffer, to prevent parsing an */
    /* empty string as the first user command        */
    /* always do a getchar() independent of OS */
    getchar();

    printf("\n");
  }
}

这是打开文件的部分(来自 main() )

  /* Get filename */
  GetFileName(argc, argv, inputfile, &json);

  /* Open the datafile */
  if ((datafile = fopen(inputfile, "rb")) == NULL) {
    PrintError(40, NULL, inputfile);
    ExitProgram();
    return(OK);
  }

EDIT2——根据 Andrew Henle 的回复,这是原型。

void    GetFileName(int, char**, char*, int*);

该函数是从定义它的同一文件中调用的。

【问题讨论】:

  • 请显示解析命令行参数并根据参数打开输入文件的代码以及读取文件名输入并尝试打开文件的代码。
  • 您应该提供minimal reproducible example
  • 可能是因为当前目录不是你想的那样。使用getcwd 获取当前工作目录并打印出来,这可能会给出提示。请提供minimal reproducible example。另请阅读:stackoverflow.com/questions/298510/…
  • 你怎么打电话给GetFileName()?您需要提供一个完整的示例,因为如果将这种古老风格的函数定义与当前的函数原型混合使用,它可能会危险
  • @Marnix 没有通用解决方案,这可能很有趣:stackoverflow.com/q/933850/898348

标签: c macos terminal binary


【解决方案1】:

我做了以下适合我的例程。

所以,举个例子:

  • 如果程序位于 /usr/mac/my-name/programs/ 位置
  • 输入的文件名为 input.dat

然后这个例程会返回:/usr/mac/my-name/programs/input.dat

感谢您的所有帮助。

#include <sys/param.h>    /* realpath()            */
#include <limits.h>       /* PATH_MAX              */
#include <mach-o/dyld.h>  /* _NSGetExectablePath() */

char *GetFullPath(const char*);

#define MAX_FILENAME_LEN 100   /* or another value */


char *GetFullPath(const char *filename)
{
  char      path_buf[PATH_MAX + 1];
  char      resolved_name[PATH_MAX + 1];
  char      *real_path;
  char      *return_path;
  uint32_t  buf_size = sizeof(path_buf);
  int       index    = 1;

  /* this functions returns the full path of the current */
  /* running application appended with var 'filename' at */
  /* the end. In case of an error it returns NULL.       */

  if ((return_path = (char *) malloc(MAX_FILENAME_LEN)) == NULL) {
    printf("GetFullPath(): error in Malloc()\n");
    return(NULL);
  }

  /* get relative path */
  if (_NSGetExecutablePath(path_buf, &buf_size) != 0) {
    /* buffer too small */
    printf("File Path too long.");
    free(return_path);
    return(NULL);
  }

  /* convert to absolute path */
  if ( (real_path = realpath(path_buf, resolved_name)) == NULL) {
    printf("Could not determine path.\n");
    free(return_path);
    return(NULL);
  }

  /* strip the application name from the end of the path */
  index = strlen(real_path) - 1;
  while (real_path[index] != '/') {
    index--;
  }

  /* now check if there's enough room in return_path */
  if (strlen(real_path) + strlen(filename) >= MAX_FILENAME_LEN) {
    printf("File path too long.\n");
    free(return_path);
    return(NULL);
  }

  /* there's enough room, copy path and filename to return_path */
  strncpy(return_path, real_path, index+1);
  /* do not try to free() real_path */
  return_path[index+1] = '\0';
  strncat(return_path, filename, strlen(filename));

  return(return_path);  /* caller must free() return_path */
}

【讨论】:

    【解决方案2】:

    我在运行正常的 linux 和 windows 上运行完全相同的源代码

    这是没有意义的。

    这是一个旧的 K&R 风格的函数定义:

    void GetFileName(nr_args, args, filename, json)
     int  nr_args;
     char **args;
     char *filename;
     int* json;
    {
       ...
    

    如果调用代码使用函数原型,则无法安全地调用该函数。 K&R 定义的函数期望其所有参数都未完成default argument promotion。该函数的原型意味着调用者不会执行这些促销活动。不匹配将导致未定义的行为。

    不要使用这种古老的功能。您不能将它们与原型一起使用,并且如果没有原型,您在函数调用中就没有类型安全。

    使用适当的、符合 C 标准的函数定义:

    void GetFileName( int  nr_args, char **args, char *filename, int* json )
    {
    ...
    

    然后为函数的所有调用提供适当的原型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-12
      • 1970-01-01
      • 1970-01-01
      • 2019-12-19
      • 2020-10-02
      • 2021-07-16
      • 2014-01-13
      相关资源
      最近更新 更多