Ich habe den folgenden Code über verschiedene Compiler ausgeführt:
int main()
{
float **a;
void **b;
b = a;
}
Soweit ich feststellen konnte, void **
handelt es sich nicht um einen generischen Zeiger, was bedeutet, dass eine Konvertierung von einem anderen Zeiger keine Warnung kompilieren oder zumindest auslösen sollte. Hier sind jedoch meine Ergebnisse (alles unter Windows):
- gcc - Wirft wie erwartet eine Warnung aus.
- g ++ - Wirft erwartungsgemäß einen Fehler aus (dies liegt an der weniger zulässigen Eingabe von C ++, oder?)
- MSVC (cl.exe) - Wirft keinerlei Warnungen, auch wenn / Wall angegeben ist.
Meine Frage ist: Vermisse ich etwas an der ganzen Sache und gibt es einen bestimmten Grund, warum MSVC keine Warnung ausgibt? MSVC gibt beim Konvertieren von void **
nach eine Warnung ausfloat **
.
Noch etwas zu beachten: Wenn ich durch a = b
die explizite Konvertierung ersetze a = (void **)b
, gibt keiner der Compiler eine Warnung aus. Ich dachte, dies sollte eine ungültige Besetzung sein. Warum sollte es dann keine Warnungen geben?
Der Grund, warum ich diese Frage stelle, ist, dass ich angefangen habe, CUDA zu lernen, und im offiziellen Programmierhandbuch ( https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#device-memory ). Der folgende Code kann gefunden werden:
// Allocate vectors in device memory
float* d_A;
cudaMalloc(&d_A, size);
die eine implizite Konvertierung nach void **
for durchführen sollte &d_A
, da das erste Argument von cudaMalloc
vom Typ ist void **
. Ein ähnlicher Code ist in der gesamten Dokumentation zu finden. Ist das nur eine schlampige Arbeit am Ende von NVIDIA oder fehlt mir wieder etwas? Da nvcc
MSVC verwendet wird, wird der Code ohne Warnungen kompiliert.
void**
ist kein generischer Zeiger. Nurvoid*
ist.(void**)
ist eine explizite Besetzung im C-Stil. Es sagt dem Compiler, er solle nicht genau hinschauen, was Sie tun, und Ihnen vertrauen. Es ist eine explizite Überschreibung des Typensicherheitssystems, und Compiler müssen grundsätzlich jede Art von Konvertierung akzeptieren. Casts im C-Stil sollten vermieden werden, sie sind viel zu kraftvoll. Verwenden Sie C ++ - Casts,static_cast
die sich beschweren, wenn Sie versuchen, etwas zu tun, das keinen Sinn ergibt.Antworten:
Diese Zuweisung ohne Umwandlung stellt eine Einschränkungsverletzung dar, sodass ein standardkonformer Compiler eine Warnung oder einen Fehler ausgibt. MSVC ist jedoch nicht vollständig kompatibel mit der C-Implementierung.
In einigen Situationen sind Zeigerkonvertierungen über eine Besetzung zulässig. Der C-Standard sagt in Abschnitt 6.3.2.3p7 Folgendes aus:
Sie können also zwischen Zeigertypen konvertieren, sofern keine Ausrichtungsprobleme vorliegen und Sie nur zurückkonvertieren (es sei denn, das Ziel ist a
char *
).Vermutlich dereferenziert diese Funktion den gegebenen Zeiger und schreibt die Adresse eines zugewiesenen Speichers. Das würde bedeuten, dass es versucht, an a zu schreiben,
float *
als wäre es avoid *
. Dies ist nicht dasselbe wie die typische Konvertierung von / nach avoid *
. Genau genommen sieht dies nach undefiniertem Verhalten aus, obwohl es "funktioniert", da moderne x86-Prozessoren (wenn sie sich nicht im Real-Modus befinden) für alle Zeigertypen dieselbe Darstellung verwenden.quelle
&d_A
sie nicht den erforderlichen Typ haben?