2017-07-13 3 views
0

J'ai un code qui les reçoit tableau binaire des valeurs 32 bits à partir d'un appareil et imprime avec vsprintf, comme ceci:Comment passer une liste variable de paramètres à vprintf de manière portable?

void print_stuff(int32_t *p, const char *format) 
{ 
    vprintf(format, (va_list)p); 
} 

(ceci est simplifié, il est assuré que les valeurs correspondent au format, etc. Fondamentalement, cela repose sur le fait que dans la norme x86 va_list est juste un pointeur (ou un tableau). Cela compile sans avertissements.

Maintenant, j'ai besoin de porter cela à ARM (arm-linux-gnueabihf) et x64, et il ne compile même pas. GCC 4-something pour ARM dit "erreur: conversion en type non-scalaire demandé"

Comment faire un va_list à partir d'un tableau binaire de façon portable? Ou au moins pour les archs 32 bits et 64 bits séparément - est possible sans aucune bibliothèque "interface d'appel native"? Si cela est impossible, existe-t-il une autre fonction de bibliothèque standard ou GNU adaptée à cette tâche?

Exemple de code qui appelle ceci:

#include <stdio.h> 
#include <stdarg.h> 
#include <stdint.h> 
#ifndef __GNUC__ 
#error Only Linux, other platforms/compilers not needed 
#endif 

int main() { 
uint32_t data[10]; 
int i; 
const char *fmt = "%x %x %x %x\n"; 
// Simulation of reading the data 
for(i = 0; i < 10, i++) data[i] = 0x100 + i; 
print_stuff(data, fmt); 
return 0; 
} 
+4

Pourquoi voudriez-vous faire encore quelque chose que vous ne sont manifestement pas censé faire? Qui a écrit ce code à l'origine? Cette personne mérite des mots très durs! –

+0

Parce que, chère Some Dude, dans la vraie vie il y a des choses comme les délais et ainsi de suite. Et je demande exactement comment coder cela correctement. – ddbug

+4

Délais? Je pense que vous avez mal orthographié l'incompétence. C'est amusant de faire des choses comme ça quand on est adolescent quand on se croit si intelligent et qu'on a tout compris. Ensuite, vous rencontrez le premier problème de portabilité et arrêtez d'être intelligent. – Art

Répondre

3

Transfert des commentaires saillants dans une approximation à une réponse.

Vous devrez revoir et réviser le code appelant pour faire le travail correctement. Ou vous abandonnez votre appel simple au vprintf() et travaillez beaucoup plus dur.

Si vous transmettez un tableau à votre fonction d'impression, vous ne passez pas un va_list. Il y a toutes sortes de choses qui fonctionnent sur une implémentation particulière qui ne fonctionne pas sur toutes les implémentations. Ce que vous apprenez, c'est que votre système actuel fonctionnait dans son habitat de niche, mais maintenant il doit sortir de son créneau, ça ne marche plus. Bienvenue dans le monde du 'comportement indéfini'. Le code qui utilise un comportement indéfini n'est pas requis pour fonctionner; il n'est pas nécessaire d'échouer non plus.

Même avec votre question révisée, il n'y a pas de façon (portable) de le faire. Période. Combien d'entrées y a-t-il dans le tableau? À quoi ressemblent les chaînes de format? Le nombre d'éléments à imprimer est-il fixe? Fondamentalement, vous pouvez être réduit à:

int n_fields = count_fields(format); 
switch (n_fields) 
{ 
case 1: printf(format, p[0]); break; 
case 2: printf(format, p[0], p[1]); break; 
… 
} 

C'est portable et fiable. Si le nombre d'éléments dans le tableau est fixe (votre code montre 4 entrées utilisées), vous n'avez pas besoin de faire le comptage ou le changement, bien sûr.

Vous pouvez rechercher libffi; il peut être en mesure de vous aider.

+0

Merci, cette solution fonctionnera pour moi. Le nombre de paramètres est variable (non représenté pour plus de simplicité). Il faut pousser les paramètres sur la pile, ce qui est limité dans mon système - mais pour un petit nombre de paramètres, cela fonctionnera. - dd – ddbug

4

Étant donné que le format est prédéfini, vous savez exactement combien de paramètres transmettre. Passez donc à votre fonction exactement les paramètres dont vous avez besoin au lieu de passer un tableau. Ensuite, vous changez votre fonction pour utiliser ... en tant que paramètre et obtenir un à partir de cela.

Ainsi, votre fonction ressemblerait à ceci:

void print_stuff(const char *format, ...) 
{ 
    va_list args; 

    va_start(args, format); 
    vprintf(format, args); 
    va_end(args); 
} 

Et vous appelleriez comme ceci:

const char *fmt = "%x %x %x %x\n"; 
... 
print_stuff(fmt, data[0], data[1], data[2], data[3]); 
+0

Cette solution a été donnée par Jonathan Leffler plus tôt dans un commentaire. et je vais le marquer comme réponse. Merci! - dd – ddbug