Sammy
Sammy

Reputation: 59

implicit declaration of function 'asprintf'

I created a program that would help convert my PHP code to a runnable c file, so I can use the PHP functions. The program runs perfectly on my system(Windows 10) but fails to run on my colleagues' systems(Windows 10 also). n my header, I created my own asprintf because the function does not exist on windows.

My asprintf.h

#ifndef ASPRINTF_H
#define ASPRINTF_H

#if defined(__GNUC__) && ! defined(_GNU_SOURCE)
#define _GNU_SOURCE /* needed for (v)asprintf, affects '#include <stdio.h>' */
#endif
#include <stdio.h>  /* needed for vsnprintf    */
#include <stdlib.h> /* needed for malloc, free */
#include <stdarg.h> /* needed for va_*         */

/*
 * vscprintf:
 * MSVC implements this as _vscprintf, thus we just 'symlink' it here
 * GNU-C-compatible compilers do not implement this, thus we implement it here
 */
#ifdef _MSC_VER
#define vscprintf _vscprintf
#endif

#ifdef __GNUC__
int vscprintf(const char *format, va_list ap)
{
    va_list ap_copy;
    va_copy(ap_copy, ap);
    int retval = vsnprintf(NULL, 0, format, ap_copy);
    va_end(ap_copy);
    return retval;
}
#endif

/*
 * asprintf, vasprintf:
 * MSVC does not implement these, thus we implement them here
 * GNU-C-compatible compilers implement these with the same names, thus we
 * don't have to do anything
 */
#ifdef _MSC_VER
int vasprintf(char **strp, const char *format, va_list ap)
{
    int len = vscprintf(format, ap);
    if (len == -1)
        return -1;
    char *str = (char*)malloc((size_t) len + 1);
    if (!str)
        return -1;
    int retval = vsnprintf(str, len + 1, format, ap);
    if (retval == -1) {
        free(str);
        return -1;
    }
    *strp = str;
    return retval;
}

int asprintf(char **strp, const char *format, ...)
{
    va_list ap;
    va_start(ap, format);
    int retval = vasprintf(strp, format, ap);
    va_end(ap);
    return retval;
}
#endif

#endif // ASPRINTF_H

My main.c

#include "asprintf.h"

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

extern char _binary_script_php_start;
extern char _binary_script_php_end;

int main(int argc, char *argv[]) {
    // EXTRACT OUR RESOURCE OBJECT INTO /tmp/test.php
    char *p = &_binary_script_php_start;
    FILE *fp = fopen("/tmp/test.php","wb");
    while ( p != &_binary_script_php_end ) {
        fputc(*p++,fp);
    }
    fclose(fp);
    // NOW READ IN OUR STANDARD ARGUMENTS AND LAUNCH OUR COMMAND
    int i = 1;
    char *cmd = "php /tmp/test.php";
    char *s = NULL;
    asprintf(&s, "%s",cmd);
    for(i = 1; i < argc; i++) {
        asprintf(&s, "%s \"%s\"",s,argv[i]);
    }
    // concatf("%s",cmd);
    // for(i = 1; i < argc; i++) {
    //     concatf("%s \"%s\"",s,argv[i]);
    // }
    // concatf(&s, "%s",cmd);
    // for(i = 1; i < argc; i++) {
    //     concatf(&s, "%s \"%s\"",s,argv[i]);
    // }
    system(s);
    free(s);
    unlink("/tmp/test.php"); // comment me out for debugging if you want
}

I was able to recreate their error by creating a new header file and changing the name of the function. so when they get:

warning: implicit declaration of function 'asprintf' [-Wimplicit-function-declaration] 29 | asprintf(&s, "%s",cmd);

I get:

warning: implicit declaration of function 'concatf' [-Wimplicit-function-declaration] 29 | concatf(&s, "%s",cmd);

Which is not making sense to me, I know for this to work, the function should be declared before the main function and that is already being done. I know I have to define _GNU_SOURCE which is being handled in my header file. Are there rules I am not adhering to? If so why would it work in my environment and not my colleagues'?

To be able to run this create a PHP file called script.php and run the following commands:

php:
    ld -r -b binary script.php data.o
exe:
    gcc main.c data.o -o runme

if working properply ./runme should run the php file.

Kindly find the source code here: https://github.com/Sammiiie/C_php_http

Upvotes: 0

Views: 1037

Answers (1)

Frankie_C
Frankie_C

Reputation: 4877

These functions, optional by standard, are defined in the document: ISO/IEC TR 24731-2.

They need to be explicitely enabled defining the constant __STDC_WANT_LIB_EXT2__ before including the header stdio.h.

From ISO/IEC TR 24731-2,5.1.1 Standard headers:

The functions, macros, and types defined in Clause 5 and its subclauses are defined by their respective headers if _STDC_WANT_LIB_EXT2 _ is defined as a macro which expands to the integer constant 1 at the point in the source file where the appropriate header is included.

I.e.

#define __STDC_WANT_LIB_EXT2__  1
#include <stdio.h>
....

In your case, to enable it only for non MS compilers, you may write:

#ifndef _MSC_VER
#define __STDC_WANT_LIB_EXT2__  1
#endif
#include <stdio.h>
....

Upvotes: 1

Related Questions