2011-11-10 26 views
6

Dize yazımının uzunluğunu bilmek için derleme zamanı optimizasyonunu kullanarak bir dize yazmak için bir makro yazmak istiyorum. Ama işaretçiyi kullanarak yanlış kullanımı tespit etmem gerekiyor.Sabit dizgeyi char * cinsinden char * cinsinden nasıl ayırt edersiniz

İşte demek istediğim: İkinci çağrı ile

void transmit(const char *data, int length); 
#define tx_string(x) transmit((x), sizeof(x) -1) 
void func(char *badmsg) { 
    tx_string("GO"); // ok 
    tx_string(badmsg); // not OK 
} 

, boyut (bir göstericinin sizeof) saçma olacaktır.

Bir dize değişmezinden başka bir şey üzerinde tx_string kullanmaya çalışırsam bir derleme zamanı hatası oluşturmak istiyorum. Bu gcc kullanıyor; Bunu yapmak için kullanabileceğim bazı gcc şeyleri var mı?

Düzenleme: Boşluklar içerebilecek veya boş bırakılamıyor olabilecek veri arabellekleriyle çalışıyorum. Gerçekten bunun için işaretçilerin kullanılmasını önlemek ve çalışma zamanı strlen() kullanımını önlemek istiyorum.

Düzenleme 2:

Bir sorun neden olacak bir örnek. Bir 16-bit mikrodenetleyiciye GO komutunu ve 16 bitlik ham (iki 8-bit karakter) bir adresi kullanarak adresini bildirmek zorunda olduğum hayali bir protokolü icat edeceğim ve adres 0'dan gitmek istiyorum.

#define GOSEQ "GO\000\000" 

void func(void) { 
    char *bad = GOSEQ; 
    tx_string(GOSEQ); // ok, sends 4 bytes: GO and two zero bytes 
    tx_string(bad); // bad, using runtime strlen sends two characters "GO" 
} 

Bunun için bir çeşit gcc yerleşik kontrol olması gerektiğine eminim. Linux çekirdeği kaynaklarını, derleme zamanı ayırma hileleri gibi çok görüyorum. Fakat ellerimi çabucak belli bir yere koyamıyorum.

Şimdiye kadar "Windows programcı" nın fikri iyi görünüyor, ancak daha anlamlı bir derleme zamanı hatası bonus olur.

#define tx_string(x) transmit(x, strlen(x)) // No need for extra parentheses 

GCC strlen çağrıyı dışarı optimize edecek, ve eminim diğer derleyiciler de olacak değilim:

cevap

9

, belki kullanabilirsiniz:

#define STRLIT(x) x "" 

argüman ise STRLIT için bir dize değişmez, bir derleme hatası alırsınız.Belirli makroya genel uyarlama

:

#define tx_string(x) transmit((x ""), sizeof(x) - 1) 
+0

Bu bir kazanan gibi görünüyor! Birinin mükemmel yerleşik test ya da başka bir şeyle karşılaşması durumunda biraz bekleyeceğim. – blueshift

4

Bunu yapabilirsin. Zamanını bu şeylere harcamayın.

Testi dosyası:

#include <string.h> 
void transmit(const char *, size_t); 
#define tx_string(x) transmit(x, strlen(x)) 
void func(void) 
{ 
    tx_string("abcdef"); 
} 

Ortaya montaj:

Ben aksamının dışına gürültü kesilmiş, bu önemli şeyler. yerine sadece 6 sayı kullanır, bu asla strlen çağırır dikkat edin: Eğer vb işaretçileri ile dize birleştirme kullanamazsınız çünkü Genelde

.LC0: 
    .string "abcdef" 

func: 
    movl $6, %esi 
    movl $.LC0, %edi 
    jmp  transmit 
+0

Tamam tx_string diyebiliriz ama boş değerlere içerebilir veri tamponları ile çalıştıkları için veya boş değerlerle sonlandırılamaz. Gerçekten bunun için işaretçilerin kullanılmasını önlemek ve çalışma zamanı strlen() kullanımını önlemek istiyorum. – blueshift

+1

@blueshift: C'de, işaretçiler ve diziler, işlevlerin bağımsız değişkenleri olarak değiştirilebilir. İşaretçilerin geçmesini önlemek için neden gerek duyuyorsunuz? Benim için mantıklı değil. Ayrıca stuntime 'strlen'ın kullanılmasını engellemeniz gerektiğinden de emin değilim. Bunu açıklar mısınız? –

+0

@Deitrich Epp: Önceki yorumumu açıklamalı. Sorunu daha net hale getirmek için düzenleyeceğim. – blueshift

1
#define tx_string(x) ("i came, i concatenated, i discarded " x, transmit((x), sizeof(x) - 1)) 

oldukça mükemmel değil bazı şakacı (1)

+0

Orada ne yaptığını görüyorum. Sinsi. Bende (+1), derlemeyi şaşırıyorum. Aslında, eğer disk dizisi x'in sağına kaydırılmışsa, oldukça iyi görünüyor .. derhal geçersiz bir şey düşünemiyorum derler. – blueshift

+0

Haklısın, Jonathan Leffler'ın cevabı küçük kusurumu çözdü. Bu arada, bazı int derlemelerinin ve değerinin bir int'nin büyüklüğü olması gerçekten şaşırtıcı olmamalı. –

İlgili konular