传递 va_list 导致无效数据

passing va_list around results in invalid data

我发现了几个关于此的问题,但其中 none 帮助我完成了这项工作。 我有以下内容。


struct general_calibration_t {
    double pressure_span;
    double pressure_offset;
    double steam_temperature_offset;
};

struct general_t {
    struct general_calibration_t calibration;
};

int generateGenericJSON(string* str, const char* json, ...) {
    char* tmp = (char*)malloc(2048);
    if (tmp == NULL)
        goto fail;

    va_list ap;
    va_start(ap, json);
    const int amount = snprintf(tmp, 2048, json, ap);
    va_end(ap);
    if (amount >= 2048 || amount < 0)
        goto release;

    string_new_value(str, tmp, amount);
    free(tmp);
    return 0;

release:
    free(tmp);
fail:
    return 1;
}

调用如下:

    struct general_t data;
    data.calibration.pressure_offset = 1.0;
    data.calibration.pressure_span = 34.8;
    data.calibration.steam_temperature_offset = 20.0;
    string calibrationStr;
    generateGenericJSON(&calibrationStr, 
        "\"Calibration\":{\"PressureSpan\":%.3f,\"PressureOffset\":%.3f,\"SteamTemperatureOffset\":%.3f}", 
        data.calibration.pressure_span, 
        data.calibration.pressure_offset, 
        data.calibration.steam_temperature_offset);

我的输出如下:

"Calibration":{"PressureSpan":0.000,"PressureOffset":0.000,"SteamTemperatureOffset":-92559631349317830736831783200707727132248687965119994463780864.000}

va_list 传递给 snprintf 时出现错误。如果我使用 va_arg 遍历函数 generateGenericJSON 中的列表,则数据是正确的。我尝试将 va_list 作为指针传递,但我得到了相同的无效数据。 将此 va_list 传递给 snprintf 我做错了什么?

What am I doing wrong in passing this va_list to snprintf?

您想使用 vsnprintf() 而不是 snprintf()


跟进 dash-o:尽量避免(出现)意大利面条代码。

处理 success/failure 不同情况的可能方法是:

int generateGenericJSON(string* str, const char* json, ...) {
  int result = 0; /* Be optimistic. */

  do { /* One time "loop" */
    char* tmp = malloc(2048); /* No need to cast malloc() and friends in C. */
    if (tmp == NULL) {
      result = -1; /* By convention -1 indicates failure. */
      break;
    }

    va_list ap;
    va_start(ap, json);
    const int amount = vsnprintf(tmp, 2048, json, ap);
    va_end(ap);

    if (amount >= 2048 || amount < 0) {
      result = -1;
      break;
    }

    string_new_value(str, tmp, amount);
  } while (0);

  free(tmp); /* Passing NULL to free is fine. */

  return result;
}