Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

char* (chaine type c)

13 réponses
Avatar
pasdespam
bonjour,

je tente d'utiliser CURL.

la plupart (et notament curl_easy_setopt) reclament des char* c
(terminés par \0) en parametre (des chaines a la mode c)

si je fais (adresse en dur)

curl_easy_setop (curl, CURLOPT_URL,
"http://monadresse:80/?action=PING");

c'est ok

mais si je passe par un osstringstream url pour construire l'adresse,
puis

url.str().c_str() en parametre j'ai une ereur a l'execution?

<url> mailformed

merci

3 réponses

1 2
Avatar
pasdespam
James Kanze wrote:

Il serait quand même intéressant de voir ton code d'origine. A
priori, je taperais sur un problème de durée de vie d'un
temporaire quelque part. Si tu appelles directement :

std::ostringstream s ;
// ...
someFunction( s.str().c_str() ) ;

ça doit marcher. (J'en fait autant assez souvent, sans
problèmes.)



void RXZoo::connect(const std::string host, const unsigned int port) {


std::cout << "Connecting to " << host << " on port " << port <<
std::endl;

/* Set up the host and port */
std::ostringstream url;
url << "http://" << host << ":" << port <<"/?action=PING";

/* wrapper C++ to C */
const std::string& sURL = url.str();
std::vector< char > buf(sURL.begin(), sURL.end());
buf.push_back('');

curl_easy_setopt(curl, CURLOPT_URL, &buf[0]);
//url.str().c_str() -> error


if (curl_easy_perform(curl) == CURLE_OK) {

/* launch thread zoo */
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,
PTHREAD_CREATE_JOINABLE);


if(pthread_create(pthreadZoo, &attr, init_pthreadZoo,
(void*)(this)) != 0)
std::cout << "Echec: Thread Zoo" << std::endl;


pthread_attr_destroy(&attr);

} else {
std::string err(errBuffer);
std::cout << err << std::endl;
}

}





En revanche, la chaîne renvoyée par s.str() est bien
un temporaire (une copie de la chaîne dans le stream), dont la
durée de vie termine à la fin de l'expression complète qui le
contient. Je ne crois pas trop à ce que le vector soit
nécessaire en soit, mais c'est une variable, avec une durée de
vie plus longue qu'un temporaire, et ça peut faire une
différence importante.



je pense aussi maintenant : dans man curl_easy_setopt

"Strings passed to libcurl as 'char *' arguments, will not be copied by
the library. Instead you should keep them available until libcurl no
longer needs them. Failing to do so will cause very odd behavior or
even crashes. libcurl will need them until you call curl_easy_cleanup(3)
or you set the same option again to use a different pointer."

TODO, mettre en membre de la classe
Avatar
James Kanze
On Jan 29, 9:47 am, Fabien LE LEZ wrote:
On Thu, 29 Jan 2009 00:11:13 -0800 (PST), James Kanze
:



[...]
>> Si, dans la doc de la bibliothèque en question, il est écrit
>> explicitement qu'en aucun cas, la fonction ne pourra modifier
>> le contenu du buffer, l'usage de "char*" est une erreur -- la
>> fonction aurait dû réclamer un "char const*"



Faut bien lire la doc.



En effet, avant d'appeler une fonction, il vaut mieux savoir ce
qu'elle fait. Savoir qui normalement doit être acquise en lisant
la doc (mais j'ai déjà eu à utiliser des fonctions où la doc se
taisait sur certains aspects important, et qu'il fallait lire
les sources).

Par exemple, la fonction CreateProcess de l'API Win32 est
tordue : on passe la ligne de commande sous forme d'une chaîne
constante... sauf si on compile en Unicode.



"The Unicode version of this function, CreateProcessW, can
modify the contents of this string. Therefore, this parameter
cannot be a pointer to read-only memory (such as a const
variable or a literal string). If this parameter is a constant
string, the function may cause an access
violation."http://msdn.microsoft.com/en-us/library/ms682425.aspx



En effet, j'ai déjà rémarqué cette anomalie. Heureusement que je
n'ai pas à utiliser cette fonction:-). (La documentation se tait
sur la taille de la chaîne qu'il faut fournir, par exemple.)
Mais d'après ce que je crois comprendre, CreateProcess, tout
seul, peut en fait être un macro pour cette fonction, selon les
options de compilation. Amusant.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
James Kanze
On Jan 29, 10:53 am, (Bruno Causse) wrote:
James Kanze wrote:
> Il serait quand même intéressant de voir ton code d'origine.
> A priori, je taperais sur un problème de durée de vie d'un
> temporaire quelque part. Si tu appelles directement :



> std::ostringstream s ;
> // ...
> someFunction( s.str().c_str() ) ;



> ça doit marcher. (J'en fait autant assez souvent, sans
> problèmes.)



void RXZoo::connect(const std::string host, const unsigned int port) {



std::cout << "Connecting to " << host << " on port " << port <<
std::endl;



/* Set up the host and port */
std::ostringstream url;
url << "http://" << host << ":" << port <<"/?action=PING";



/* wrapper C++ to C */
const std::string& sURL = url.str();
std::vector< char > buf(sURL.begin(), sURL.end());
buf.push_back('');



C'est donc la version modifiée, non celle qui te pose des
problèmes.

curl_easy_setopt(curl, CURLOPT_URL, &buf[0]);
//url.str().c_str() -> error



Jusque là, ça ne doit pas poser de problème. Cependant...

if (curl_easy_perform(curl) == CURLE_OK) {



/* launch thread zoo */
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,
PTHREAD_CREATE_JOINABLE);



if(pthread_create(pthreadZoo, &attr, init_pthreadZoo,
(void*)(this)) != 0)
std::cout << "Echec: Thread Zoo" << std::endl;



pthread_attr_destroy(&attr);

} else {
std::string err(errBuffer);
std::cout << err << std::endl;
}



}
> En revanche, la chaîne renvoyée par s.str() est bien
> un temporaire (une copie de la chaîne dans le stream), dont la
> durée de vie termine à la fin de l'expression complète qui le
> contient. Je ne crois pas trop à ce que le vector soit
> nécessaire en soit, mais c'est une variable, avec une durée de
> vie plus longue qu'un temporaire, et ça peut faire une
> différence importante.



je pense aussi maintenant : dans man curl_easy_setopt



"Strings passed to libcurl as 'char *' arguments, will not be
copied by the library. Instead you should keep them available
until libcurl no longer needs them. Failing to do so will
cause very odd behavior or even crashes. libcurl will need
them until you call curl_easy_cleanup(3) or you set the same
option again to use a different pointer."



TODO, mettre en membre de la classe



En effet. Que le pointeur provient d'un std::string ou d'un
std::vector, pas d'importance. Mais il faut absolument qu'il
provient d'un objet dont la durée de vie s'étend jusqu'à cet
appel à curl_easy_cleanup.

Et on a un bon exemple de comment ne pas concevoir une
bibliothèque.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
1 2