Variadic parametrelerini va_list
'a dönüştüren bir kod var, daha sonra listeyi vsnprintf
olarak adlandırılan bir işleve iletir. Bu, Windows ve OS X üzerinde iyi çalışıyor, ancak Linux'ta garip sonuçlarla başarısız oluyor. Aşağıdaki kod örneğiva_list aksaklığı Linux'ta
:
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
char *myPrintfInner(const char *message, va_list params)
{
va_list *original = ¶ms;
size_t length = vsnprintf(NULL, 0, message, *original);
char *final = (char *) malloc((length + 1) * sizeof(char));
int result = vsnprintf(final, length + 1, message, params);
printf("vsnprintf result: %d\r\n", result);
printf("%s\r\n", final);
return final;
}
char *myPrintf(const char *message, ...)
{
va_list va_args;
va_start(va_args, message);
size_t length = vsnprintf(NULL, 0, message, va_args);
char *final = (char *) malloc((length + 1) * sizeof(char));
int result = vsnprintf(final, length + 1, message, va_args);
printf("vsnprintf result: %d\r\n", result);
printf("%s\r\n", final);
va_end(va_args);
return final;
}
int main(int argc, char **argv)
{
char *test = myPrintf("This is a %s.", "test");
char *actual = "This is a test.";
int result = strcmp(test, actual);
if (result != 0)
{
printf("%d: Test failure!\r\n", result);
}
else
{
printf("Test succeeded.\r\n");
}
return 0;
}
ikinci vsnprintf
aramanın çıkışı 17 ve strcmp
sonucu 31 olduğu; ama vsnprintf
This is a test.
olarak görülmeye 17 döneceğini neden 15 karakter olan olsun NULL
eklemek ve gördüğüm ama konuyu ele almazlarsa 16.
İlgili konuları alamadım:
- Pass va_list or pointer to va_list?
- Passing one va_list as a parameter to another @ Mat'ın cevap ile
(ıyeniden ediyorumnesnesi, izin verilmez), bu, birbirine bağladığım ilk ilişkili iş parçacığı etrafında gelir. Bu yüzden yerine bu kodu teşebbüs:
Ama (C99 modunda gcc 4.4.5) benim derleyici banaBir va_list bir işaretçi oluşturmak için izin verilir ve başka o işaretçi pass:
char *myPrintfInner(const char *message, va_list params) { va_list *original = ¶ms; size_t length = vsnprintf(NULL, 0, message, params); char *final = (char *) malloc((length + 1) * sizeof(char)); int result = vsnprintf(final, length + 1, message, *original); printf("vsnprintf result: %d\r\n", result); printf("%s\r\n", final); return final; }
hangisi, per the C99 spec (Bölüm 7.15 dipnotu), çalışmalıdır işlev, bu durumda orijinal işlev 'u, diğer işlev döndürdikten sonra orijinal listenin daha fazla kullanmasını sağlayabilir.
myPrintfInner
ilk satırında ilgili bu hatayı veriyor:
test.c: In function ‘myPrintfInner’:
test.c:8: warning: initialization from incompatible pointer type
Ve çıkan ikili çevresinde ilk defa tam olarak aynı etkiyi üretir .
Bulunan bu: Is GCC mishandling a pointer to a va_list passed to a function?
önerilen geçici çözüm (çalışması garanti, ama pratikte yaptığımız değildi) kullanmaktır arg_copy
ilk: Sorun olduğunu
char *myPrintfInner(const char *message, va_list params)
{
va_list args_copy;
va_copy(args_copy, params);
size_t length = vsnprintf(NULL, 0, message, params);
char *final = (char *) malloc((length + 1) * sizeof(char));
int result = vsnprintf(final, length + 1, message, args_copy);
printf("vsnprintf result: %d\r\n", result);
printf("%s\r\n", final);
return final;
}
'myPrintf' işlevinizde' return' ifadesi eksik. Derleyicinin sizi bu konuda uyarmasını beklerdim. –
bah, humbug! Kopyalayıp yapıştırın. –
Yeni kodunuz, eskiyle aynı şeyi yapıyor: "orijinal", "params" a işaret ediyor, bu yüzden, * orijinali, "param" kelimesinin geçmesiyle tamamen aynıdır. Asıl sorunun, va_list'in nasıl çalıştığını anlamıyor olmanız gibi görünüyor: aslında argüman yığıtının işaretçileridir ve işaretçi, kullanıldığı gibi artar. Yani, aynı va_list'i iki kez kullandığınızda, ikincisini, argüman listesinin sonundaki işaretçiyi artırdığınız zaman. –