如果我的函数来自另一个 .c,我可以知道调用我的函数的文件名和函数名吗?

Can I know the file and function names from where my function is called if it's from another .c?

我正在开发一个库,我想知道有关我提供的其中一个函数的调用者的一些数据。特别是,我需要知道调用我的函数(重新定义的 malloc)的文件名、函数名和行。

编辑:这是一个最小的工作示例,我可以在其中检测用户何时调用 malloc 并将他“重定向”到我自己的 malloc 函数:

main.c:

#include <stdio.h>
#include <stdlib.h>
#include "myLib.h"

int main(){
    printf("Inside main, asking for memory\n");

    int *p = malloc(sizeof(int));
    *p = 3;

    free(p);

    return 0;
}

myLib.c:

#include "myLib.h"

void * myAlloc (size_t size){
    void * p = NULL;

    fprintf(stderr, "Inside my own malloc\n");
    
    p = (malloc)(size);

    return p;
    
}
#undef malloc
#define malloc(size) myAlloc(size)

myLib.h:

#ifndef MYLIB_H
#define MYLIB_H

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>

#define malloc(size) myAlloc(size)

void * myAlloc(size_t size);
#endif

我试过使用 _FILE_ _func_ 和 _LINE_关键字,但我无法让它工作,因为它在不同的模块中。

你可以:

//mylib.h
#ifndef MYLIB_H
#define MYLIB_H

#include <stdlib.h>
// replace malloc in case it's already a macro
#ifdef malloc
#undef malloc
#endif

// I believe that from the standards point of view, this is undefined behavior
#define malloc(size) my_alloc(size, __FILE__, __LINE__, __func__)

#ifdef __GNUC__
// Allow compiler to do static checking.
__attribute__((__alloc_size__(1), __malloc__))
#endif
void *my_alloc(size_t size, const char *file, int line, const char *func);
//    ^^^^^^^^ I do not like camelCase case - one snake case to rule them all.

#endif

// mylib.c
#include "mylib.h" // do not ever mix uppercase and lowercase in filenames
#undef malloc      // undef malloc so we don't call ourselves recursively
#include <stdio.h>

void *my_alloc(size_t size, const char *file, int line, const char *func){
    fprintf(stderr, "Och my god, you wouldn't believe it!\n"
          "A function %s in file %s at line %d called malloc!\n",
         func, file, line);
    return malloc(size);
}

您可能还会看到如何 assert does it. If you are aiming at glibc, read glibc docs replacing malloc

正如您发现的那样,用户可能会执行 (malloc)(size) cicumvent 宏扩展。你可以这样做:

void *my_alloc(size_t size, const char *file, int line, const char *func);

static inline void *MY_ALLOC(size_t size) {
    return my_alloc(size, NULL, 0, NULL);
}
#define MY_ALLOC(size)  my_alloc(size, __FILE__, __LINE__, __func__)

// if called with `malloc()` then MY_ALLOC is expanded
// if called as `(malloc)`, then just expands to MY_ALLOC.
#define malloc MY_ALLOC

int main() {
    malloc(10);    // calls my_alloc(10, "main.c", 62, "main");
    (malloc)(20);  // calls my_alloc(20, NULL, 0, NULL);
}

GLIBC 为 malloc()、free()...定义了隐藏符号,它们被称为 __libc_malloc()、__libc_free()...

因此,您可以极大地简化调试宏。

m.h中,只需定义如下:

#if DEBUG_LEVEL > 0

extern void *__libc_malloc (size_t bytes);

extern void *myMalloc(size_t size, const char *filename, const char *funcname, int line);

#define malloc(size) myMalloc(size, __FILE__, __FUNCTION__, __LINE__)

#endif

然后你可以写一个程序定义myMalloc()如下(例如文件名是m.c):

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "m.h"

#if DEBUG_LEVEL > 0

void *myMalloc(
              size_t      size,
              const char *filename,
              const char *funcname,
              int         line
             ) {

  fprintf(stderr, "malloc(%zu) called from %s/%s()#%d\n", size, filename, funcname, line);

  return __libc_malloc(size);
}

#endif

char *dup_str(char *string) {

  char *str = malloc(strlen(string) + 1);

  strcpy(str, string);

  return str;
}

int main(int ac, char *av[]) {

  char *str;

  if (av[1]) {
    str = dup_str(av[1]);
  } else {
    str = dup_str("NULL");
  }

  printf("String = '%s'\n", str);

  free(str);

  return 0;
}

当您在非调试模式下编译此示例程序时:

$ gcc m.c -DDEBUG_LEVEL=0
$ ./a.out azerty
String = 'azerty'

当您在调试模式下编译程序时:

$ gcc m.c -DDEBUG_LEVEL=1
$ ./a.out azerty
malloc(7) called from m.c/dup_str()#27
String = 'azerty'