Deutsch English Français Italiano |
<uu416t$33u55$1@news.xmission.com> View for Bookmarking (what is this?) Look up another Usenet article |
Path: ...!weretis.net!feeder8.news.weretis.net!feeder6.news.weretis.net!xmission!nnrp.xmission!.POSTED.shell.xmission.com!not-for-mail From: gazelle@shell.xmission.com (Kenny McCormack) Newsgroups: comp.lang.c Subject: Casting the return value of ... Date: Thu, 28 Mar 2024 15:09:17 -0000 (UTC) Organization: The official candy of the new Millennium Message-ID: <uu416t$33u55$1@news.xmission.com> Injection-Date: Thu, 28 Mar 2024 15:09:17 -0000 (UTC) Injection-Info: news.xmission.com; posting-host="shell.xmission.com:166.70.8.4"; logging-data="3274917"; mail-complaints-to="abuse@xmission.com" X-Newsreader: trn 4.0-test77 (Sep 1, 2010) Originator: gazelle@shell.xmission.com (Kenny McCormack) Bytes: 3655 Lines: 65 I think this is a variation on that old CLC standard "Why you should not cast the return value of malloc()". Caution: POSIX (non-strict ISO) stuff coming up. If this bothers you, please hit "next" right now. I frequently write "interposer" functions as shared libraries (on Linux). Generally, this requires using dlsym() and RTLD_NEXT to get a pointer to the "real" function, so that you can call that as part of your interposer routine. I have always done it like this (e.g., for a function returning char *, taking 2 size_t args - just to pick an arbitrary example to make things more concrete): char *someFunction(size_t,size_t) { static char * (*real_someFunction) (size_t,size_t); if (!real_someFunction) real_someFunction = (char * (*real_someFunction) (size_t,size_t)) dlsym(RTLD_NEXT,"someFunction"); .... } This works fine (and compiles clean with the usual -W -Wall -Werror). But here's the thing. Is the casting of the result of dlsym() necessary? Isn't this the same as "casting the return value of malloc()", where you don't need to cast it since it auto-magically gets casted by being assigned to the thing on the left of the assignment? Note that it is duplicative, having to specify the type info for the function pointer twice - once in the declaration of the pointer and then again in the dlsym() call. It'd be better (in terms of maintenance) if you only had to do it once. But here's where it gets interesting. In the man page for dlopen(), we find this example code and a long detailed comment: double (*cosine)(double); .... cosine = (double (*)(double)) dlsym(handle, "cos"); /* According to the ISO C standard, casting between function pointers and 'void *', as done above, produces undefined results. POSIX.1-2003 and POSIX.1-2008 accepted this state of affairs and proposed the following workaround: *(void **) (&cosine) = dlsym(handle, "cos"); This (clumsy) cast conforms with the ISO C standard and will avoid any compiler warnings. The 2013 Technical Corrigendum to POSIX.1-2008 (a.k.a. POSIX.1-2013) improved matters by requiring that conforming implementations support casting 'void *' to a function pointer. Nevertheless, some compilers (e.g., gcc with the '-pedantic' option) may complain about the cast used in this program. */ So, they seem to think the cast is necessary - or at least a good idea, Are they right? And why do we even need the "clumsy" cast? Why not just: cosine = dlsym(handle, "cos"); -- You are a dreadful man, Kenny, for all your ways are the ways of death. - Rick C Hodgin - (P.S. -> https://www.youtube.com/watch?v=sMmTkKz60W8)