strlen dans le préprocesseur C?
Est-il possible de mettre en œuvre strlen()
dans le C préprocesseur?
Donné:
#define MYSTRING "bob"
Est-il une macro du préprocesseur, X
, qui permettez-moi de dire:
#define MYSTRING_LEN X(MYSTRING)
- Pourquoi auriez-vous besoin de faire cela? N'est-il pas normal d'avoir de la macro étendre à strlen("bob")?
- Quel est le problème avec
#define MYSTRING_LEN 3
? Je peux voir qu'il serait utile si, comme vous suffirait de changerMYSTRING
et ne pas s'inquiéterMYSTRING_LEN
... - Je suis en train de travailler sur un petit système embarqué et je suis critique courte du code de l'espace. La strlen() la fonction n'est pas nécessaire. Je suis en essayant d'éviter de coder en dur la longueur des constantes pour toutes les chaînes.
- Double Possible de Déterminer #définit la longueur de la chaîne au moment de la compilation.
- Est-il une autre question qui parle de comment le faire pour une constante tableau de pointeurs sur des chaines comme
static const char* strings[] = { "foo", "hello" }
? La pratique de la macro ci-dessous semble rupture dans ce cas, par exemple,enum string_names { S_FOO = 0, S_HELLO }; static const size_t const string_lengths[] = { STRLEN(strings[S_FOO]), STRLEN(strings[S_HELLO]) }
Ici tous lesstring_lengths
membres 8 (taille du pointeur de la souris) au lieu de la longueur de la chaîne. Peut-être que j'ai juste besoin de donner et de l'utilisationstrlen
au moment de l'exécution :/
Vous devez vous connecter pour publier un commentaire.
Il n'utilise pas le préprocesseur, mais sizeof est résolu au moment de la compilation. Si votre chaîne est dans un tableau, vous pouvez l'utiliser pour déterminer sa longueur au moment de la compilation:
Garder à l'esprit le fait que
STRLEN
notamment le terminateur null, contrairement àstrlen()
.strlen
, pourriez-vous ne pas#define STRLEN(s) ( (sizeof(s)/sizeof(s[0])) - sizeof(s[0]) )
?- 1
. Dans ce cas, la plupart du temps.-1
et puis on est rentrés et (en)corrigé.memcpy()
, il est donc logique de le garder commestrlen()+1
. Aussi, pour le -1 cas, en l'utilisant sur une chaîne vide serait mauvais.static const char string[] = "bob\0and\0mary"
ferait rapport une longueur supérieure à"bob"
.#include <string.h>
.#include <string.h>
alors une bien meilleure approche est d'écrire votre propre strnlen en C puis#include "myString.h"
Lors de la programmation en C, vous gagnez la possibilité de compter dans les moyens qui ne nécessitent pas de pile récursive en fonction de la descente. Cette solution semble bon, mais c'est un bug en attente de se produire pour tous, mais le plus simple des cas. Fondamentalement, vous seriez mieux avec#define BOB "bob"
et#define BOB_LEN 3
#define BOB_LEN 3
est plus susceptible de finir dans les larmes que ce que j'ai décrit, mais ta remarque est valide. L'écriture de code en C signifie souvent tentant le bug des destins. La décision vient vraiment à ce compromis que vous êtes prêt à faire.sizeof "bob"
fonctionnera très bien.char *string = "bob";
.#define NELS(array) (sizeof(array)/sizeof(array[0]))
pour le "nombre d'éléments". Cela fonctionne pour n'importe quel tableau et est beaucoup moins trompeur que STRLEN.Oui:
#define MYSTRING_LEN(s) strlen(s)
Dans la plupart des compilateurs, cela produira une constante de compilation pour un argument constant ... et vous ne pouvez pas faire mieux que cela.
En d'autres termes: vous n'avez pas besoin d'une macro, il suffit d'utiliser strlen; le compilateur est assez intelligent pour faire le travail pour vous.
int f() {char XYZ[strlen(s)]; ...}
n'est pas valide C89 programme tout enint f() {char XYZ[sizeof(s)]; ...}
serait.-1
ou+1
à l'un d'eux, mais mon point est toujours debout - même si le compilateur est probablement l'optimiser il ne signifie pas qu'il est applicable à toutes les situations.sizeof
opérateur peut être utilisé dans un constant de l'expression (de longueur variable, à l'exception des tableaux).strlen
vous ne pouvez pas être. On peut supposer que l'utilisation du préprocesseur implique un besoin pour une expression constante, sinon cela ne serait pas fait en utilisant le préprocesseur. Donc, oui, vous pouvez faire mieux questrlen
et l'utilisationsizeof("foo")
qui donne une expression constante. Il peut être utilisé dans d'autres contextes que l'expression le compilateur est optimisé pour une constante de compilation. Ces optimisations ne changent pas le sens du programme, et de ne pas faire de cette expression une expression constante.Que vous pouvez faire:
Qui dit 4 sur ma machine, en raison de la valeur null est ajouté à la fin.
Bien sûr, cela ne fonctionne que pour une constante de chaîne.
À l'aide de MSVC 16 (
cl.exe -Wall /TC file.c
) ce:sorties:
La taille de la chaîne, plus le caractère NUL.
char
, etsizeof
travaux sur les tableaux comme avec tout autre type.Généralement la C le pré-processeur ne fait pas de transformer les données, il ne le remplace. Cela signifie que vous pourriez être en mesure d'effectuer une telle opération, à condition que vous polluer votre C le pré-processeur de l'espace de noms avec les données de mise en œuvre (fonctionnelle) persistante des structures de données.
Cela dit, vous ne voulez vraiment pas à faire ce que l'ensemble ", a ajouté la fonctionnalité" échoue spectaculairement une fois que vous passez à autre chose qu'une chaîne de caractères. La C le pré-processeur n'a pas de notion de type de données, ni de la notion de mémoire de référence (utile si vous vouliez la longueur d'une chaîne de caractères stockée dans une variable). En gros, ce serait un plaisir "de voir dans quelle mesure vous pourriez prendre" l'exercice physique, mais à la fin, vous avez un MYSTRING_LEN qui ne prenne une courte distance de l'objectif.
En outre, la C le pré-processeur du manque d'espaces de nom signifie qu'une telle macro extension du système serait ne pas être de containable. On aurait pu prendre soin de garder les noms générés à partir d'interférer avec d'autres macros. En fin de compte, vous serait probablement à court de mémoire dans le pré-processeur pour toute utilisation importante, comme le pré-processeur n'est pas vraiment construit pour accueillir un nom pour chaque personnage étant convertie en "unité" jeton, et un nom pour chaque "unité" jeton d'être compressé dans sa dernière notation décimale.