簡體   English   中英

為什么接受 void* 指針作為 function 參數,因為它總是在 C 的 function 主體中轉換為相同類型?

[英]Why accept void* pointer as a function argument when it is always cast to the same type in the function body in C?

我看到一些 C 函數將void*指針作為參數,然后在 function 的主體中,指針的唯一用法是在每次使用時將其轉換為相同的類型(在我的例子中為unsigned char* ) .

我知道這是一個合法的操作,我的問題是為什么不只接受一個指向unsigned char的指針而不是接受一個void*並每次都轉換它? 這樣做是否有一些性能改進或一些限制?

如果你想要一個代碼示例,請查看參數datum處的profileImage方法(第 933 行)(演員表位於第 989 行):

MagickExport MagickBooleanType ProfileImage(Image *image,const char *name,
   const void *datum,const size_t length,ExceptionInfo *exception)
 {
 #define ProfileImageTag  "Profile/Image"
 #ifndef TYPE_XYZ_8
   #define TYPE_XYZ_8 (COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(1))
 #endif
 #define ThrowProfileException(severity,tag,context) \
 { \
   if (profile != (StringInfo *) NULL) \
      profile=DestroyStringInfo(profile); \
   if (cms_context != (cmsContext) NULL) \
     cmsDeleteContext(cms_context); \
   if (source_info.profile != (cmsHPROFILE) NULL) \
     (void) cmsCloseProfile(source_info.profile); \
   if (target_info.profile != (cmsHPROFILE) NULL) \
     (void) cmsCloseProfile(target_info.profile); \
   ThrowBinaryException(severity,tag,context); \
 }
  
   MagickBooleanType
     status;
  
   StringInfo
     *profile;
  
   assert(image != (Image *) NULL);
   assert(image->signature == MagickCoreSignature);
   assert(name != (const char *) NULL);
   if (IsEventLogging() != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   if ((datum == (const void *) NULL) || (length == 0))
     {
       char
         *next;
  
       /*
         Delete image profile(s).
       */
       ResetImageProfileIterator(image);
       for (next=GetNextImageProfile(image); next != (const char *) NULL; )
       {
         if (IsOptionMember(next,name) != MagickFalse)
           {
             (void) DeleteImageProfile(image,next);
             ResetImageProfileIterator(image);
           }
         next=GetNextImageProfile(image);
       }
       return(MagickTrue);
     }
   /*
     Add a ICC, IPTC, or generic profile to the image.
   */
   status=MagickTrue;
   profile=AcquireStringInfo((size_t) length);
   SetStringInfoDatum(profile,(unsigned char *) datum);
   if ((LocaleCompare(name,"icc") != 0) && (LocaleCompare(name,"icm") != 0))
     status=SetImageProfile(image,name,profile,exception);
   else
     {
       const StringInfo
         *icc_profile;
  
       icc_profile=GetImageProfile(image,"icc");
       if ((icc_profile != (const StringInfo *) NULL) &&
           (CompareStringInfo(icc_profile,profile) == 0))
         {
           const char
             *value;
  
           value=GetImageProperty(image,"exif:ColorSpace",exception);
           (void) value;
           if (LocaleCompare(value,"1") != 0)
             (void) SetsRGBImageProfile(image,exception);
           value=GetImageProperty(image,"exif:InteroperabilityIndex",exception);
           if (LocaleCompare(value,"R98.") != 0)
             (void) SetsRGBImageProfile(image,exception);
           icc_profile=GetImageProfile(image,"icc");
         }
       if ((icc_profile != (const StringInfo *) NULL) &&
           (CompareStringInfo(icc_profile,profile) == 0))
         {
           profile=DestroyStringInfo(profile);
           return(MagickTrue);
         }
 #if !defined(MAGICKCORE_LCMS_DELEGATE)
       (void) ThrowMagickException(exception,GetMagickModule(),
         MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn",
         "'%s' (LCMS)",image->filename);
 #else
       {
         cmsContext
           cms_context;
  
         CMSExceptionInfo
           cms_exception;
  
         LCMSInfo
           source_info,
           target_info;
  
         /*
           Transform pixel colors as defined by the color profiles.
         */
         cms_exception.image=image;
         cms_exception.exception=exception;
         cms_context=cmsCreateContext(NULL,&cms_exception);
         if (cms_context == (cmsContext) NULL)
           {
             profile=DestroyStringInfo(profile);
             ThrowBinaryException(ResourceLimitError,
               "ColorspaceColorProfileMismatch",name);
           }
         cmsSetLogErrorHandlerTHR(cms_context,CMSExceptionHandler);
         source_info.profile=cmsOpenProfileFromMemTHR(cms_context,
           GetStringInfoDatum(profile),(cmsUInt32Number)
           GetStringInfoLength(profile));
         if (source_info.profile == (cmsHPROFILE) NULL)
           {
             profile=DestroyStringInfo(profile);
             cmsDeleteContext(cms_context);
             ThrowBinaryException(ResourceLimitError,
               "ColorspaceColorProfileMismatch",name);
           }
         if ((cmsGetDeviceClass(source_info.profile) != cmsSigLinkClass) &&
             (icc_profile == (StringInfo *) NULL))
           status=SetImageProfile(image,name,profile,exception);
         else
           {
             CacheView
               *image_view;
  
             cmsColorSpaceSignature
               signature;
  
             cmsHTRANSFORM
               *magick_restrict transform;
  
             cmsUInt32Number
               flags;
  
             MagickBooleanType
               highres;
  
             MagickOffsetType
               progress;
  
             ssize_t
               y;
  
             target_info.profile=(cmsHPROFILE) NULL;
             if (icc_profile != (StringInfo *) NULL)
               {
                 target_info.profile=source_info.profile;
                 source_info.profile=cmsOpenProfileFromMemTHR(cms_context,
                   GetStringInfoDatum(icc_profile),(cmsUInt32Number)
                   GetStringInfoLength(icc_profile));
                 if (source_info.profile == (cmsHPROFILE) NULL)
                   ThrowProfileException(ResourceLimitError,
                     "ColorspaceColorProfileMismatch",name);
               }
             highres=MagickTrue;
 #if !defined(MAGICKCORE_HDRI_SUPPORT) || (MAGICKCORE_QUANTUM_DEPTH > 16)
             {
               const char
                 *artifact;
  
               artifact=GetImageArtifact(image,"profile:highres-transform");
               if (IsStringFalse(artifact) != MagickFalse)
                 highres=MagickFalse;
             }
 #endif
             SetLCMSInfoScale(&source_info,1.0);
             SetLCMSInfoTranslate(&source_info,0.0);
             source_info.colorspace=sRGBColorspace;
             source_info.channels=3;
             switch (cmsGetColorSpace(source_info.profile))
             {
               case cmsSigCmykData:
               {
                 source_info.colorspace=CMYKColorspace;
                 source_info.channels=4;
                 if (highres != MagickFalse)
                   {
                     source_info.type=(cmsUInt32Number) TYPE_CMYK_DBL;
                     SetLCMSInfoScale(&source_info,100.0);
                   }
 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
                 else
                   source_info.type=(cmsUInt32Number) TYPE_CMYK_8;
 #elif (MAGICKCORE_QUANTUM_DEPTH == 16)
                 else
                   source_info.type=(cmsUInt32Number) TYPE_CMYK_16;
 #endif
                 break;
               }
               case cmsSigGrayData:
               {
                 source_info.colorspace=GRAYColorspace;
                 source_info.channels=1;
                 if (highres != MagickFalse)
                   source_info.type=(cmsUInt32Number) TYPE_GRAY_DBL;
 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
                 else
                   source_info.type=(cmsUInt32Number) TYPE_GRAY_8;
 #elif (MAGICKCORE_QUANTUM_DEPTH == 16)
                 else
                   source_info.type=(cmsUInt32Number) TYPE_GRAY_16;
 #endif
                 break;
               }
               case cmsSigLabData:
               {
                 source_info.colorspace=LabColorspace;
                 if (highres != MagickFalse)
                   {
                     source_info.type=(cmsUInt32Number) TYPE_Lab_DBL;
                     source_info.scale[0]=100.0;
                     source_info.scale[1]=255.0;
                     source_info.scale[2]=255.0;
                     source_info.translate[1]=(-0.5);
                     source_info.translate[2]=(-0.5);
                   }
 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
                 else
                   source_info.type=(cmsUInt32Number) TYPE_Lab_8;
 #elif (MAGICKCORE_QUANTUM_DEPTH == 16)
                 else
                   source_info.type=(cmsUInt32Number) TYPE_Lab_16;
 #endif
                 break;
               }
               case cmsSigRgbData:
               {
                 source_info.colorspace=sRGBColorspace;
                 if (highres != MagickFalse)
                   source_info.type=(cmsUInt32Number) TYPE_RGB_DBL;
 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
                 else
                   source_info.type=(cmsUInt32Number) TYPE_RGB_8;
 #elif (MAGICKCORE_QUANTUM_DEPTH == 16)
                 else
                   source_info.type=(cmsUInt32Number) TYPE_RGB_16;
 #endif
                 break;
               }
               case cmsSigXYZData:
               {
                 source_info.colorspace=XYZColorspace;
                 if (highres != MagickFalse)
                   source_info.type=(cmsUInt32Number) TYPE_XYZ_DBL;
 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
                 else
                   source_info.type=(cmsUInt32Number) TYPE_XYZ_8;
 #elif (MAGICKCORE_QUANTUM_DEPTH == 16)
                 else
                   source_info.type=(cmsUInt32Number) TYPE_XYZ_16;
 #endif
                 break;
               }
               default:
                 ThrowProfileException(ImageError,
                   "ColorspaceColorProfileMismatch",name);
             }
             signature=cmsGetPCS(source_info.profile);
             if (target_info.profile != (cmsHPROFILE) NULL)
               signature=cmsGetColorSpace(target_info.profile);
             SetLCMSInfoScale(&target_info,1.0);
             SetLCMSInfoTranslate(&target_info,0.0);
             target_info.channels=3;
             switch (signature)
             {
               case cmsSigCmykData:
               {
                 target_info.colorspace=CMYKColorspace;
                 target_info.channels=4;
                 if (highres != MagickFalse)
                   {
                     target_info.type=(cmsUInt32Number) TYPE_CMYK_DBL;
                     SetLCMSInfoScale(&target_info,0.01);
                   }
 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
                 else
                   target_info.type=(cmsUInt32Number) TYPE_CMYK_8;
 #elif (MAGICKCORE_QUANTUM_DEPTH == 16)
                 else
                   target_info.type=(cmsUInt32Number) TYPE_CMYK_16;
 #endif
                 break;
               }
               case cmsSigGrayData:
               {
                 target_info.colorspace=GRAYColorspace;
                 target_info.channels=1;
                 if (highres != MagickFalse)
                   target_info.type=(cmsUInt32Number) TYPE_GRAY_DBL;
 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
                 else
                   target_info.type=(cmsUInt32Number) TYPE_GRAY_8;
 #elif (MAGICKCORE_QUANTUM_DEPTH == 16)
                 else
                   target_info.type=(cmsUInt32Number) TYPE_GRAY_16;
 #endif
                 break;
               }
               case cmsSigLabData:
               {
                 target_info.colorspace=LabColorspace;
                 if (highres != MagickFalse)
                   {
                     target_info.type=(cmsUInt32Number) TYPE_Lab_DBL;
                     target_info.scale[0]=0.01;
                     target_info.scale[1]=1/255.0;
                     target_info.scale[2]=1/255.0;
                     target_info.translate[1]=0.5;
                     target_info.translate[2]=0.5;
                   }
 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
                 else
                   target_info.type=(cmsUInt32Number) TYPE_Lab_8;
 #elif (MAGICKCORE_QUANTUM_DEPTH == 16)
                 else
                   target_info.type=(cmsUInt32Number) TYPE_Lab_16;
 #endif
                 break;
               }
               case cmsSigRgbData:
               {
                 target_info.colorspace=sRGBColorspace;
                 if (highres != MagickFalse)
                   target_info.type=(cmsUInt32Number) TYPE_RGB_DBL;
 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
                 else
                   target_info.type=(cmsUInt32Number) TYPE_RGB_8;
 #elif (MAGICKCORE_QUANTUM_DEPTH == 16)
                 else
                   target_info.type=(cmsUInt32Number) TYPE_RGB_16;
 #endif
                 break;
               }
               case cmsSigXYZData:
               {
                 target_info.colorspace=XYZColorspace;
                 if (highres != MagickFalse)
                   target_info.type=(cmsUInt32Number) TYPE_XYZ_DBL;
 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
                 else
                   target_info.type=(cmsUInt32Number) TYPE_XYZ_8;
 #elif (MAGICKCORE_QUANTUM_DEPTH == 16)
                 else
                   source_info.type=(cmsUInt32Number) TYPE_XYZ_16;
 #endif
                 break;
               }
               default:
                 ThrowProfileException(ImageError,
                   "ColorspaceColorProfileMismatch",name);
             }
             switch (image->rendering_intent)
             {
               case AbsoluteIntent:
               {
                 target_info.intent=INTENT_ABSOLUTE_COLORIMETRIC;
                 break;
               }
               case PerceptualIntent:
               {
                 target_info.intent=INTENT_PERCEPTUAL;
                 break;
               }
               case RelativeIntent:
               {
                 target_info.intent=INTENT_RELATIVE_COLORIMETRIC;
                 break;
               }
               case SaturationIntent:
               {
                 target_info.intent=INTENT_SATURATION;
                 break;
               }
               default:
               {
                 target_info.intent=INTENT_PERCEPTUAL;
                 break;
               }
             }
             flags=cmsFLAGS_HIGHRESPRECALC;
 #if defined(cmsFLAGS_BLACKPOINTCOMPENSATION)
             if (image->black_point_compensation != MagickFalse)
               flags|=cmsFLAGS_BLACKPOINTCOMPENSATION;
 #endif
             transform=AcquireTransformTLS(&source_info,&target_info,flags,
               cms_context);
             if (transform == (cmsHTRANSFORM *) NULL)
               ThrowProfileException(ImageError,"UnableToCreateColorTransform",
                 name);
             /*
               Transform image as dictated by the source & target image profiles.
             */
             source_info.pixels=AcquirePixelTLS(image->columns,
               source_info.channels,highres);
             target_info.pixels=AcquirePixelTLS(image->columns,
               target_info.channels,highres);
             if ((source_info.pixels == (void **) NULL) ||
                 (target_info.pixels == (void **) NULL))
               {
                 target_info.pixels=DestroyPixelTLS(target_info.pixels);
                 source_info.pixels=DestroyPixelTLS(source_info.pixels);
                 transform=DestroyTransformTLS(transform);
                 ThrowProfileException(ResourceLimitError,
                   "MemoryAllocationFailed",image->filename);
               }
             if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
               {
                 target_info.pixels=DestroyPixelTLS(target_info.pixels);
                 source_info.pixels=DestroyPixelTLS(source_info.pixels);
                 transform=DestroyTransformTLS(transform);
                 if (source_info.profile != (cmsHPROFILE) NULL)
                   (void) cmsCloseProfile(source_info.profile);
                 if (target_info.profile != (cmsHPROFILE) NULL)
                   (void) cmsCloseProfile(target_info.profile);
                 return(MagickFalse);
               }
             if (target_info.colorspace == CMYKColorspace)
               (void) SetImageColorspace(image,target_info.colorspace,exception);
             progress=0;
             image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
             #pragma omp parallel for schedule(static) shared(status) \
               magick_number_threads(image,image,image->rows,1)
 #endif
             for (y=0; y < (ssize_t) image->rows; y++)
             {
               const int
                 id = GetOpenMPThreadId();
  
               MagickBooleanType
                 sync;
  
               Quantum
                 *magick_restrict q;
  
               if (status == MagickFalse)
                 continue;
               q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
                 exception);
               if (q == (Quantum *) NULL)
                 {
                   status=MagickFalse;
                   continue;
                 }
               if (highres != MagickFalse)
                 TransformDoublePixels(id,image,&source_info,&target_info,
                   transform,q);
               else
                 TransformQuantumPixels(id,image,&source_info,&target_info,
                   transform,q);
               sync=SyncCacheViewAuthenticPixels(image_view,exception);
               if (sync == MagickFalse)
                 status=MagickFalse;
               if (image->progress_monitor != (MagickProgressMonitor) NULL)
                 {
                   MagickBooleanType
                     proceed;
  
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
                   #pragma omp atomic
 #endif
                   progress++;
                   proceed=SetImageProgress(image,ProfileImageTag,progress,
                     image->rows);
                   if (proceed == MagickFalse)
                     status=MagickFalse;
                 }
             }
             image_view=DestroyCacheView(image_view);
             (void) SetImageColorspace(image,target_info.colorspace,exception);
             switch (signature)
             {
               case cmsSigRgbData:
               {
                 image->type=image->alpha_trait == UndefinedPixelTrait ?
                   TrueColorType : TrueColorAlphaType;
                 break;
               }
               case cmsSigCmykData:
               {
                 image->type=image->alpha_trait == UndefinedPixelTrait ?
                   ColorSeparationType : ColorSeparationAlphaType;
                 break;
               }
               case cmsSigGrayData:
               {
                 image->type=image->alpha_trait == UndefinedPixelTrait ?
                   GrayscaleType : GrayscaleAlphaType;
                 break;
               }
               default:
                 break;
             }
             target_info.pixels=DestroyPixelTLS(target_info.pixels);
             source_info.pixels=DestroyPixelTLS(source_info.pixels);
             transform=DestroyTransformTLS(transform);
             if ((status != MagickFalse) &&
                 (cmsGetDeviceClass(source_info.profile) != cmsSigLinkClass))
               status=SetImageProfile(image,name,profile,exception);
             if (target_info.profile != (cmsHPROFILE) NULL)
               (void) cmsCloseProfile(target_info.profile);
           }
         (void) cmsCloseProfile(source_info.profile);
         cmsDeleteContext(cms_context);
       }
 #endif
     }
   profile=DestroyStringInfo(profile);
   return(status);
 }

在有問題的代碼中......

我認為他們只是寫了糟糕的代碼(在這個特殊情況下,我只想說;而且:我們有時都會寫糟糕的代碼——我們邊走邊學/成長)。 如果他們想要那種類型,他們應該使用unsigned char unsigned char* ,如果他們希望參數是可選的,可以偶爾傳入NULL來代替值,那么他們應該使用 unsigned char*。 void*不鼓勵用於“通用編程”目的,除非確實有必要,因為它會阻止編譯器進行嚴格的類型檢查,並可能導致更多錯誤。 請注意,在 pthread 庫和我下面的示例中,它確實是必要的 這些都是void*的好用法。 正確使用和使用得當以及應該使用的時候都是好的。

如何使用void*類型的“通用函數”來接受和返回任何類型

void*使用得當,與速度、效率無關。 相反,它與多功能性有關。

接受void*的函數是通用函數(我不知道這是“官方”還是“公認術語”;我只是這么稱呼它們)。 例如,它們可以讓您傳遞函數或注冊可以做任何您喜歡的事情的函數。

這是一個簡單的例子。 想象一下,一個通用庫允許您注冊回調 function,它將在稍后調用:

// Define `func_t` as a function ptr whose signature looks like this:
// `void* func(void*);`
typedef void* (*func_t)(void*);

// a generic library function (not written by the user of the library)
void* register_callback(func_t user_func, void* args_to_user_func)
{
    // have this function call the function passed to it, and return what it
    // returns, for demo purposes
    return user_func(args_to_user_func);
}

現在,這個通用庫的用戶可以傳入他們想要的任何 function 接受並返回他們想要的任何類型。 前任:

// EXAMPLE 1

// user function 1
void* print_int(void* int_ptr)
{
    int val = *(int*)int_ptr; // extract the integer from the passed-in arg
    printf("%i\n", val);

    return NULL;
}

int int_to_print = 7;
register_callback(print_int, &int_to_print);


// EXAMPLE 2

typedef struct my_struct_s
{
    int i;
    float f;
    bool b;
} my_struct_t;

// user function 2
void* print_struct(void* my_struct_ptr_in)
{
    my_struct_t *my_struct_ptr = (my_struct_t*)my_struct_ptr_in;

    printf("%i, %f, %s\n", 
        my_struct_ptr->i
        my_struct_ptr->f,
        my_struct_ptr->b ? "true" : "false");

    return NULL;
}

my_struct_t my_struct = 
{
    .i = 7,
    .f = 17.1308;
    .b = true;
};
register_callback(print_struct, &my_struct);

看到這里的美了嗎? register_callback()現在是一種通用類型 function,它可以接受回調 function,它可以執行任何操作打印任何內容並接收任何類型的變量。 它的可能性是無限的。

pthread 庫需要這種類型的“通用函數”行為來運行線程。 您必須傳入一個您希望線程運行的 function,以及一個包含您需要 function 接收的任何 arguments 的void* 要傳遞“多個”args,請通過 ptr 將它們傳遞給包含多個 args 的結構,正如我在上面演示的那樣。

要在 C++ 中執行此操作,您可以執行與上面相同的代碼,或者您可以改用此模板巫術:我的回答:How to use variadic templates (parameter packs) in C++ to pass a variadic list of arguments to a sub-function

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM