簡體   English   中英

macOS 上的 C 程序無法打開其輸入文件

[英]C-program on macOS cannot open its input file

我有一個使用 gcc 和 makefile 在 macOS High Sierra 上構建的 C 程序。 程序做的第一件事是讀取二進制輸入文件。 文件名可以從終端命令行與 shell 命令一起指定,或者程序將在未指定時要求它。

我的問題是,當輸入文件沒有與 shell 命令一起指定時,程序返回一個錯誤,說它無法打開文件。

以下是哪些有效,哪些無效:(程序和輸入文件在同一目錄中)

  1. 打開終端
  2. 從命令行輸入:

    ./program_name –i input.dat

=> 工作正常

  1. 打開終端
  2. 從命令行類型:

    ./程序名稱

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

=> 錯誤打開文件

  1. 打開 Finder 並轉到包含程序和輸入文件的目錄
  2. 雙擊 program_name 圖標
  3. 程序在終端啟動並提示: Inputfile:
  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*);

該函數是從定義它的同一個文件中調用的。

我在 linux 和 windows 上運行完全相同的源代碼,它可以正常工作

那是沒有意義的。

這是一個舊的 K&R 風格的函數定義:

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

如果調用代碼使用函數原型,則無法安全地調用該函數。 K&R 定義的函數期望它的所有參數都沒有完成默認參數提升 該函數的原型意味着調用者不會執行這些提升。 不匹配將導致未定義的行為。

不要使用這么古老的函數。 您不能將它們與原型一起使用,並且沒有原型,您在函數調用中就沒有類型安全性。

使用正確的、符合 C 標准的函數定義:

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

然后為所有對該函數的調用提供一個合適的原型。

我做了以下對我有用的例程。

所以,作為一個例子:

  • 如果程序位於 /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 */
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM