Czy można wyłuskać wskaźnik void bez rzutowania typów w języku programowania C?
Ponadto, czy istnieje sposób na uogólnienie funkcji, która może otrzymać wskaźnik i przechowywać go we wskaźniku void, a używając tego wskaźnika void, czy możemy utworzyć funkcję uogólnioną?
na przykład:
void abc(void *a, int b)
{
if(b==1)
printf("%d",*(int*)a); // If integer pointer is received
else if(b==2)
printf("%c",*(char*)a); // If character pointer is received
else if(b==3)
printf("%f",*(float*)a); // If float pointer is received
}
Chcę, aby ta funkcja była ogólna bez używania instrukcji if-else - czy to możliwe?
Również jeśli istnieją dobre artykuły internetowe, które wyjaśniają pojęcie void pointer, byłoby korzystne, gdybyś mógł podać adresy URL.
Czy możliwa jest również arytmetyka wskaźnika ze wskaźnikami do pustych przestrzeni?
źródło
void *
wskaźnikach tak samo jakchar *
, ale to nie jest standard i nie powinieneś na nim polegać.W języku C a
void *
można przekonwertować na wskaźnik do obiektu innego typu bez jawnego rzutowania:void abc(void *a, int b) { int *test = a; /* ... */
Nie pomaga to jednak w pisaniu funkcji w bardziej ogólny sposób.
Nie można wyłuskać a
void *
poprzez konwersję go na inny typ wskaźnika, ponieważ wyłuskiwanie wskaźnika jest uzyskiwaniem wartości wskazywanego obiektu. Nakedvoid
nie jest prawidłowym typem, więc usunięcie dostępuvoid *
nie jest możliwe.Arytmetyka wskaźników polega na zmianie wartości wskaźnika przez wielokrotność
sizeof
wskazanych obiektów. Ponownie, ponieważvoid
nie jest to prawdziwy typ,sizeof(void)
nie ma znaczenia, więc arytmetyka wskaźnika nie jest poprawnavoid *
. (Niektóre implementacje na to pozwalają, używając równoważnej arytmetyki wskaźnika dlachar *
.)źródło
void abc(void *a, int b)
. Ale dlaczego nie użyćvoid abc(int *a, int b)
, skoro w swojej funkcji ostatecznie zdefiniujeszint *test = a;
, zapisałoby to jedną zmienną, a nie widzę żadnych innych zalet definiowania innej zmiennej. Widzę wiele kodów napisanych w ten sposób, używającvoid *
jako parametrów i rzutujących zmienne później w funkcji. Ale skoro ta funkcja jest napisana przez autora, więc musi znać użycie zmiennej, więc po co jej używaćvoid *
? DziękiNależy mieć świadomość, że w C, w przeciwieństwie do Javy czy C #, nie ma absolutnie żadnej możliwości pomyślnego „odgadnięcia” typu obiektu, na który
void*
wskazuje wskaźnik. Coś podobnegogetClass()
po prostu nie istnieje, ponieważ nigdzie nie można znaleźć tych informacji. Z tego powodu rodzaj „generycznego”, którego szukasz, zawsze zawiera jawną metainformację, taką jakint b
w twoim przykładzie lub ciąg formatu wprintf
rodzinie funkcji.źródło
Wskaźnik void jest znany jako wskaźnik ogólny, który może odnosić się do zmiennych dowolnego typu.
źródło
Jak dotąd moje zaniżenie dotyczące wskaźnika void jest następujące.
Gdy zmienna wskaźnikowa jest zadeklarowana przy użyciu słowa kluczowego void - staje się zmienną wskaźnikową ogólnego przeznaczenia. Adres dowolnej zmiennej dowolnego typu danych (char, int, float itp.) Można przypisać do zmiennej wskaźnika void.
main() { int *p; void *vp; vp=p; }
Ponieważ do wskaźnika void można przypisać inny wskaźnik typu danych, użyłem go w funkcji absolut_value (kod pokazany poniżej). Aby zrobić ogólną funkcję.
Próbowałem napisać prosty kod C, który przyjmuje liczbę całkowitą lub zmiennoprzecinkową jako argument i stara się, aby był + ve, jeśli jest ujemny. Napisałem następujący kod,
#include<stdio.h> void absolute_value ( void *j) // works if used float, obviously it must work but thats not my interest here. { if ( *j < 0 ) *j = *j * (-1); } int main() { int i = 40; float f = -40; printf("print intiger i = %d \n",i); printf("print float f = %f \n",f); absolute_value(&i); absolute_value(&f); printf("print intiger i = %d \n",i); printf("print float f = %f \n",f); return 0; }
Ale otrzymywałem błąd, więc dowiedziałem się, że moje rozumienie ze wskaźnikiem void jest nieprawidłowe :(. Więc teraz przejdę do zbierania punktów, dlaczego tak jest.
Na temat wskaźników pustki muszę lepiej zrozumieć, że.
Musimy typecastować zmienną void pointer, aby ją usunąć. Dzieje się tak, ponieważ ze wskaźnikiem void nie jest powiązany żaden typ danych. W żaden sposób kompilator nie może wiedzieć (lub zgadywać?), Na jaki typ danych wskazuje wskaźnik void. Tak więc, aby wziąć dane wskazywane przez wskaźnik void, wpisujemy je na maszynie z poprawnym typem danych przechowywanych w lokalizacji void pointers.
void main() { int a=10; float b=35.75; void *ptr; // Declaring a void pointer ptr=&a; // Assigning address of integer to void pointer. printf("The value of integer variable is= %d",*( (int*) ptr) );// (int*)ptr - is used for type casting. Where as *((int*)ptr) dereferences the typecasted void pointer variable. ptr=&b; // Assigning address of float to void pointer. printf("The value of float variable is= %f",*( (float*) ptr) ); }
Wskaźnik void może być naprawdę przydatny, jeśli programista nie jest pewien typu danych wprowadzanych przez użytkownika końcowego. W takim przypadku programista może użyć wskaźnika void, aby wskazać lokalizację nieznanego typu danych. Program można ustawić w taki sposób, aby prosić użytkownika o poinformowanie o typie danych, a rzutowanie typu może być wykonywane zgodnie z informacjami wprowadzonymi przez użytkownika. Fragment kodu znajduje się poniżej.
void funct(void *a, int z) { if(z==1) printf("%d",*(int*)a); // If user inputs 1, then he means the data is an integer and type casting is done accordingly. else if(z==2) printf("%c",*(char*)a); // Typecasting for character pointer. else if(z==3) printf("%f",*(float*)a); // Typecasting for float pointer }
Inną ważną kwestią, o której należy pamiętać w przypadku wskaźników void, jest to, że arytmetyka wskaźnika nie może być wykonywana w przypadku wskaźnika void.
void *ptr; int a; ptr=&a; ptr++; // This statement is invalid and will result in an error because 'ptr' is a void pointer variable.
Więc teraz zrozumiałem, jaki był mój błąd. Poprawiam to samo.
Bibliografia :
http://www.antoarts.com/void-pointers-in-c/
http://www.circuitstoday.com/void-pointers-in-c .
Nowy kod jest przedstawiony poniżej.
#include<stdio.h> #define INT 1 #define FLOAT 2 void absolute_value ( void *j, int *n) { if ( *n == INT) { if ( *((int*)j) < 0 ) *((int*)j) = *((int*)j) * (-1); } if ( *n == FLOAT ) { if ( *((float*)j) < 0 ) *((float*)j) = *((float*)j) * (-1); } } int main() { int i = 0,n=0; float f = 0; printf("Press 1 to enter integer or 2 got float then enter the value to get absolute value\n"); scanf("%d",&n); printf("\n"); if( n == 1) { scanf("%d",&i); printf("value entered before absolute function exec = %d \n",i); absolute_value(&i,&n); printf("value entered after absolute function exec = %d \n",i); } if( n == 2) { scanf("%f",&f); printf("value entered before absolute function exec = %f \n",f); absolute_value(&f,&n); printf("value entered after absolute function exec = %f \n",f); } else printf("unknown entry try again\n"); return 0; }
Dziękuję Ci,
źródło
Nie, to niemożliwe. Jaki typ powinna mieć wyłuskana wartość?
źródło
void abc(void *a, int b) { char *format[] = {"%d", "%c", "%f"}; printf(format[b-1], a); }
źródło
printf
. Ta odpowiedź ma na to dobry przykład.int b
wyliczeniem, ale dokonanie jakiejkolwiek późniejszej zmiany tego wyliczenia spowodowałoby przerwanie tej funkcji.Jedynym prostym sposobem, jaki widzę, jest użycie przeciążenia .. które nie jest dostępne w języku programowania C AFAIK.
Czy zastanawiałeś się nad językiem programowania C ++ w swoim programie? Czy jest jakieś ograniczenie, które zabrania jego używania?
źródło
Oto krótka wskazówka na temat
void
wskaźników: https://www.learncpp.com/cpp-tutorial/613-void-pointers/Zakładając, że pamięć urządzenia jest bajt adresowalnych i nie wymaga wyrównane dostępy, najbardziej ogólny i atomowej (najbliżej reprezentacji poziomu maszyna) sposób interpretacji
void*
jest jako wskaźnik do a-bajt,uint8_t*
. Rzutowanie avoid*
na auint8_t*
pozwoliłoby ci na przykład wydrukować pierwsze 1/2/4/8 / dowolną liczbę bajtów zaczynając od tego adresu, ale nie możesz zrobić nic więcej.uint8_t* byte_p = (uint8_t*)p; for (uint8_t* i = byte_p; i < byte_p + 8; i++) { printf("%x ",*i); }
źródło
Możesz łatwo wydrukować pustą drukarkę
int p=15; void *q; q=&p; printf("%d",*((int*)q));
źródło
void
ma taki sam rozmiar jakint
?void
wskaźnika, to drukowanieint
pod adresem pamięci, który zawiera wskaźnik (który w tym przypadku byłby wartościąp
).Ponieważ C jest językiem z typami statycznymi i silnymi typami, przed kompilacją należy zdecydować o typie zmiennej. Kiedy spróbujesz emulować typy generyczne w C, w końcu spróbujesz przepisać C ++ ponownie, więc lepiej byłoby zamiast tego użyć C ++.
źródło
void pointer to ogólny wskaźnik. Adres dowolnego typu danych dowolnej zmiennej może być przypisany do wskaźnika void.
int a = 10; float b = 3.14; void *ptr; ptr = &a; printf( "data is %d " , *((int *)ptr)); //(int *)ptr used for typecasting dereferencing as int ptr = &b; printf( "data is %f " , *((float *)ptr)); //(float *)ptr used for typecasting dereferencing as float
źródło
Nie można wyłuskać wskaźnika bez określenia jego typu, ponieważ różne typy danych będą miały różne rozmiary w pamięci, tj. Int to 4 bajty, a char to 1 bajt.
źródło
Zasadniczo w C „typy” są sposobem interpretacji bajtów w pamięci. Na przykład, jaki jest następujący kod
struct Point { int x; int y; }; int main() { struct Point p; p.x = 0; p.y = 0; }
Mówi: „Kiedy uruchamiam main, chcę przydzielić 4 (rozmiar liczby całkowitej) + 4 (rozmiar liczby całkowitej) = 8 (łącznie bajtów) pamięci. Kiedy piszę„ .x ”jako lwartość na wartości z etykietą typu Wskaż na czas kompilacji, pobierz dane z lokalizacji pamięci wskaźnika plus cztery bajty. Podaj zwracanej wartości etykietę czasu kompilacji „int”.
Wewnątrz komputera w czasie wykonywania struktura „Point” wygląda następująco:
00000000 00000000 00000000 00000000 00000000 00000000 00000000
A oto jak
void*
może wyglądać twój typ danych: (zakładając komputer 32-bitowy)10001010 11111001 00010010 11000101
źródło
To nie zadziała, ale void * może bardzo pomóc w zdefiniowaniu ogólnego wskaźnika do funkcji i przekazaniu go jako argumentu do innej funkcji (podobnie jak wywołanie zwrotne w Javie) lub zdefiniowaniu struktury podobnej do oop.
źródło